diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/cfg/cfg.cpp | 139 | ||||
| -rw-r--r-- | src/core/hle/service/cfg/cfg.h | 164 | ||||
| -rw-r--r-- | src/core/hle/service/cfg/cfg_i.cpp | 57 | ||||
| -rw-r--r-- | src/core/hle/service/cfg/cfg_s.cpp | 62 | ||||
| -rw-r--r-- | src/core/hle/service/cfg/cfg_u.cpp | 219 |
5 files changed, 304 insertions, 337 deletions
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp index 2d26c9330..d42682883 100644 --- a/src/core/hle/service/cfg/cfg.cpp +++ b/src/core/hle/service/cfg/cfg.cpp | |||
| @@ -6,8 +6,11 @@ | |||
| 6 | 6 | ||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "common/string_util.h" | 8 | #include "common/string_util.h" |
| 9 | #include "common/file_util.h" | ||
| 9 | 10 | ||
| 11 | #include "core/file_sys/archive_systemsavedata.h" | ||
| 10 | #include "core/file_sys/file_backend.h" | 12 | #include "core/file_sys/file_backend.h" |
| 13 | #include "core/settings.h" | ||
| 11 | #include "core/hle/service/cfg/cfg.h" | 14 | #include "core/hle/service/cfg/cfg.h" |
| 12 | #include "core/hle/service/cfg/cfg_i.h" | 15 | #include "core/hle/service/cfg/cfg_i.h" |
| 13 | #include "core/hle/service/cfg/cfg_s.h" | 16 | #include "core/hle/service/cfg/cfg_s.h" |
| @@ -23,7 +26,7 @@ const u64 CONSOLE_UNIQUE_ID = 0xDEADC0DE; | |||
| 23 | const ConsoleModelInfo CONSOLE_MODEL = { NINTENDO_3DS_XL, { 0, 0, 0 } }; | 26 | const ConsoleModelInfo CONSOLE_MODEL = { NINTENDO_3DS_XL, { 0, 0, 0 } }; |
| 24 | const u8 CONSOLE_LANGUAGE = LANGUAGE_EN; | 27 | const u8 CONSOLE_LANGUAGE = LANGUAGE_EN; |
| 25 | const char CONSOLE_USERNAME[0x14] = "CITRA"; | 28 | const char CONSOLE_USERNAME[0x14] = "CITRA"; |
| 26 | /// This will be initialized in CFGInit, and will be used when creating the block | 29 | /// This will be initialized in Init, and will be used when creating the block |
| 27 | UsernameBlock CONSOLE_USERNAME_BLOCK; | 30 | UsernameBlock CONSOLE_USERNAME_BLOCK; |
| 28 | /// TODO(Subv): Find out what this actually is | 31 | /// TODO(Subv): Find out what this actually is |
| 29 | const u8 SOUND_OUTPUT_MODE = 2; | 32 | const u8 SOUND_OUTPUT_MODE = 2; |
| @@ -47,6 +50,140 @@ static std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer; | |||
| 47 | static Service::FS::ArchiveHandle cfg_system_save_data_archive; | 50 | static Service::FS::ArchiveHandle cfg_system_save_data_archive; |
| 48 | static const std::vector<u8> cfg_system_savedata_id = { 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00 }; | 51 | static const std::vector<u8> cfg_system_savedata_id = { 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00 }; |
| 49 | 52 | ||
| 53 | void GetCountryCodeString(Service::Interface* self) { | ||
| 54 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 55 | u32 country_code_id = cmd_buff[1]; | ||
| 56 | |||
| 57 | if (country_code_id >= country_codes.size() || 0 == country_codes[country_code_id]) { | ||
| 58 | LOG_ERROR(Service_CFG, "requested country code id=%d is invalid", country_code_id); | ||
| 59 | cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw; | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | cmd_buff[1] = 0; | ||
| 64 | cmd_buff[2] = country_codes[country_code_id]; | ||
| 65 | } | ||
| 66 | |||
| 67 | void GetCountryCodeID(Service::Interface* self) { | ||
| 68 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 69 | u16 country_code = cmd_buff[1]; | ||
| 70 | u16 country_code_id = 0; | ||
| 71 | |||
| 72 | // The following algorithm will fail if the first country code isn't 0. | ||
| 73 | DEBUG_ASSERT(country_codes[0] == 0); | ||
| 74 | |||
| 75 | for (u16 id = 0; id < country_codes.size(); ++id) { | ||
| 76 | if (country_codes[id] == country_code) { | ||
| 77 | country_code_id = id; | ||
| 78 | break; | ||
| 79 | } | ||
| 80 | } | ||
| 81 | |||
| 82 | if (0 == country_code_id) { | ||
| 83 | LOG_ERROR(Service_CFG, "requested country code name=%c%c is invalid", country_code & 0xff, country_code >> 8); | ||
| 84 | cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw; | ||
| 85 | cmd_buff[2] = 0xFFFF; | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | |||
| 89 | cmd_buff[1] = 0; | ||
| 90 | cmd_buff[2] = country_code_id; | ||
| 91 | } | ||
| 92 | |||
| 93 | void SecureInfoGetRegion(Service::Interface* self) { | ||
| 94 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 95 | |||
| 96 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 97 | cmd_buff[2] = Settings::values.region_value; | ||
| 98 | } | ||
| 99 | |||
| 100 | void GenHashConsoleUnique(Service::Interface* self) { | ||
| 101 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 102 | u32 app_id_salt = cmd_buff[1]; | ||
| 103 | |||
| 104 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 105 | cmd_buff[2] = 0x33646D6F ^ (app_id_salt & 0xFFFFF); // 3dmoo hash | ||
| 106 | cmd_buff[3] = 0x6F534841 ^ (app_id_salt & 0xFFFFF); | ||
| 107 | |||
| 108 | LOG_WARNING(Service_CFG, "(STUBBED) called app_id_salt=0x%X", app_id_salt); | ||
| 109 | } | ||
| 110 | |||
| 111 | void GetRegionCanadaUSA(Service::Interface* self) { | ||
| 112 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 113 | |||
| 114 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 115 | |||
| 116 | u8 canada_or_usa = 1; | ||
| 117 | if (canada_or_usa == Settings::values.region_value) { | ||
| 118 | cmd_buff[2] = 1; | ||
| 119 | } else { | ||
| 120 | cmd_buff[2] = 0; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | void GetSystemModel(Service::Interface* self) { | ||
| 125 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 126 | u32 data; | ||
| 127 | |||
| 128 | // TODO(Subv): Find out the correct error codes | ||
| 129 | cmd_buff[1] = Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8, | ||
| 130 | reinterpret_cast<u8*>(&data)).raw; | ||
| 131 | cmd_buff[2] = data & 0xFF; | ||
| 132 | } | ||
| 133 | |||
| 134 | void GetModelNintendo2DS(Service::Interface* self) { | ||
| 135 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 136 | u32 data; | ||
| 137 | |||
| 138 | // TODO(Subv): Find out the correct error codes | ||
| 139 | cmd_buff[1] = Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8, | ||
| 140 | reinterpret_cast<u8*>(&data)).raw; | ||
| 141 | |||
| 142 | u8 model = data & 0xFF; | ||
| 143 | if (model == Service::CFG::NINTENDO_2DS) | ||
| 144 | cmd_buff[2] = 0; | ||
| 145 | else | ||
| 146 | cmd_buff[2] = 1; | ||
| 147 | } | ||
| 148 | |||
| 149 | void GetConfigInfoBlk2(Service::Interface* self) { | ||
| 150 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 151 | u32 size = cmd_buff[1]; | ||
| 152 | u32 block_id = cmd_buff[2]; | ||
| 153 | u8* data_pointer = Memory::GetPointer(cmd_buff[4]); | ||
| 154 | |||
| 155 | if (data_pointer == nullptr) { | ||
| 156 | cmd_buff[1] = -1; // TODO(Subv): Find the right error code | ||
| 157 | return; | ||
| 158 | } | ||
| 159 | |||
| 160 | cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data_pointer).raw; | ||
| 161 | } | ||
| 162 | |||
| 163 | void GetConfigInfoBlk8(Service::Interface* self) { | ||
| 164 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 165 | u32 size = cmd_buff[1]; | ||
| 166 | u32 block_id = cmd_buff[2]; | ||
| 167 | u8* data_pointer = Memory::GetPointer(cmd_buff[4]); | ||
| 168 | |||
| 169 | if (data_pointer == nullptr) { | ||
| 170 | cmd_buff[1] = -1; // TODO(Subv): Find the right error code | ||
| 171 | return; | ||
| 172 | } | ||
| 173 | |||
| 174 | cmd_buff[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data_pointer).raw; | ||
| 175 | } | ||
| 176 | |||
| 177 | void UpdateConfigNANDSavegame(Service::Interface* self) { | ||
| 178 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 179 | cmd_buff[1] = Service::CFG::UpdateConfigNANDSavegame().raw; | ||
| 180 | } | ||
| 181 | |||
| 182 | void FormatConfig(Service::Interface* self) { | ||
| 183 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 184 | cmd_buff[1] = Service::CFG::FormatConfig().raw; | ||
| 185 | } | ||
| 186 | |||
| 50 | ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { | 187 | ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { |
| 51 | // Read the header | 188 | // Read the header |
| 52 | SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data()); | 189 | SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data()); |
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h index 3488c40d0..ff76dc9dc 100644 --- a/src/core/hle/service/cfg/cfg.h +++ b/src/core/hle/service/cfg/cfg.h | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include "core/hle/result.h" | 8 | #include "core/hle/result.h" |
| 9 | #include "core/hle/service/service.h" | ||
| 9 | 10 | ||
| 10 | namespace Service { | 11 | namespace Service { |
| 11 | namespace CFG { | 12 | namespace CFG { |
| @@ -40,6 +41,169 @@ struct SaveConfigBlockEntry { | |||
| 40 | u16 flags; ///< The flags of the block, possibly used for access control | 41 | u16 flags; ///< The flags of the block, possibly used for access control |
| 41 | }; | 42 | }; |
| 42 | 43 | ||
| 44 | // TODO(Link Mauve): use a constexpr once MSVC starts supporting it. | ||
| 45 | #define C(code) ((code)[0] | ((code)[1] << 8)) | ||
| 46 | |||
| 47 | static const std::array<u16, 187> country_codes = { | ||
| 48 | 0, C("JP"), 0, 0, 0, 0, 0, 0, // 0-7 | ||
| 49 | C("AI"), C("AG"), C("AR"), C("AW"), C("BS"), C("BB"), C("BZ"), C("BO"), // 8-15 | ||
| 50 | C("BR"), C("VG"), C("CA"), C("KY"), C("CL"), C("CO"), C("CR"), C("DM"), // 16-23 | ||
| 51 | C("DO"), C("EC"), C("SV"), C("GF"), C("GD"), C("GP"), C("GT"), C("GY"), // 24-31 | ||
| 52 | C("HT"), C("HN"), C("JM"), C("MQ"), C("MX"), C("MS"), C("AN"), C("NI"), // 32-39 | ||
| 53 | C("PA"), C("PY"), C("PE"), C("KN"), C("LC"), C("VC"), C("SR"), C("TT"), // 40-47 | ||
| 54 | C("TC"), C("US"), C("UY"), C("VI"), C("VE"), 0, 0, 0, // 48-55 | ||
| 55 | 0, 0, 0, 0, 0, 0, 0, 0, // 56-63 | ||
| 56 | C("AL"), C("AU"), C("AT"), C("BE"), C("BA"), C("BW"), C("BG"), C("HR"), // 64-71 | ||
| 57 | C("CY"), C("CZ"), C("DK"), C("EE"), C("FI"), C("FR"), C("DE"), C("GR"), // 72-79 | ||
| 58 | C("HU"), C("IS"), C("IE"), C("IT"), C("LV"), C("LS"), C("LI"), C("LT"), // 80-87 | ||
| 59 | C("LU"), C("MK"), C("MT"), C("ME"), C("MZ"), C("NA"), C("NL"), C("NZ"), // 88-95 | ||
| 60 | C("NO"), C("PL"), C("PT"), C("RO"), C("RU"), C("RS"), C("SK"), C("SI"), // 96-103 | ||
| 61 | C("ZA"), C("ES"), C("SZ"), C("SE"), C("CH"), C("TR"), C("GB"), C("ZM"), // 104-111 | ||
| 62 | C("ZW"), C("AZ"), C("MR"), C("ML"), C("NE"), C("TD"), C("SD"), C("ER"), // 112-119 | ||
| 63 | C("DJ"), C("SO"), C("AD"), C("GI"), C("GG"), C("IM"), C("JE"), C("MC"), // 120-127 | ||
| 64 | C("TW"), 0, 0, 0, 0, 0, 0, 0, // 128-135 | ||
| 65 | C("KR"), 0, 0, 0, 0, 0, 0, 0, // 136-143 | ||
| 66 | C("HK"), C("MO"), 0, 0, 0, 0, 0, 0, // 144-151 | ||
| 67 | C("ID"), C("SG"), C("TH"), C("PH"), C("MY"), 0, 0, 0, // 152-159 | ||
| 68 | C("CN"), 0, 0, 0, 0, 0, 0, 0, // 160-167 | ||
| 69 | C("AE"), C("IN"), C("EG"), C("OM"), C("QA"), C("KW"), C("SA"), C("SY"), // 168-175 | ||
| 70 | C("BH"), C("JO"), 0, 0, 0, 0, 0, 0, // 176-183 | ||
| 71 | C("SM"), C("VA"), C("BM") // 184-186 | ||
| 72 | }; | ||
| 73 | |||
| 74 | #undef C | ||
| 75 | |||
| 76 | /** | ||
| 77 | * CFG::GetCountryCodeString service function | ||
| 78 | * Inputs: | ||
| 79 | * 1 : Country Code ID | ||
| 80 | * Outputs: | ||
| 81 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 82 | * 2 : Country's 2-char string | ||
| 83 | */ | ||
| 84 | void GetCountryCodeString(Service::Interface* self); | ||
| 85 | |||
| 86 | /** | ||
| 87 | * CFG::GetCountryCodeID service function | ||
| 88 | * Inputs: | ||
| 89 | * 1 : Country Code 2-char string | ||
| 90 | * Outputs: | ||
| 91 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 92 | * 2 : Country Code ID | ||
| 93 | */ | ||
| 94 | void GetCountryCodeID(Service::Interface* self); | ||
| 95 | |||
| 96 | /** | ||
| 97 | * CFG::GetConfigInfoBlk2 service function | ||
| 98 | * Inputs: | ||
| 99 | * 0 : 0x00010082 | ||
| 100 | * 1 : Size | ||
| 101 | * 2 : Block ID | ||
| 102 | * 3 : Descriptor for the output buffer | ||
| 103 | * 4 : Output buffer pointer | ||
| 104 | * Outputs: | ||
| 105 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 106 | */ | ||
| 107 | void GetConfigInfoBlk2(Service::Interface* self); | ||
| 108 | |||
| 109 | /** | ||
| 110 | * CFG::SecureInfoGetRegion service function | ||
| 111 | * Inputs: | ||
| 112 | * 1 : None | ||
| 113 | * Outputs: | ||
| 114 | * 0 : Result Header code | ||
| 115 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 116 | * 2 : Region value loaded from SecureInfo offset 0x100 | ||
| 117 | */ | ||
| 118 | void SecureInfoGetRegion(Service::Interface* self); | ||
| 119 | |||
| 120 | /** | ||
| 121 | * CFG::GenHashConsoleUnique service function | ||
| 122 | * Inputs: | ||
| 123 | * 1 : 20 bit application ID salt | ||
| 124 | * Outputs: | ||
| 125 | * 0 : Result Header code | ||
| 126 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 127 | * 2 : Hash/"ID" lower word | ||
| 128 | * 3 : Hash/"ID" upper word | ||
| 129 | */ | ||
| 130 | void GenHashConsoleUnique(Service::Interface* self); | ||
| 131 | |||
| 132 | /** | ||
| 133 | * CFG::GetRegionCanadaUSA service function | ||
| 134 | * Inputs: | ||
| 135 | * 1 : None | ||
| 136 | * Outputs: | ||
| 137 | * 0 : Result Header code | ||
| 138 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 139 | * 2 : 1 if the system is a Canada or USA model, 0 otherwise | ||
| 140 | */ | ||
| 141 | void GetRegionCanadaUSA(Service::Interface* self); | ||
| 142 | |||
| 143 | /** | ||
| 144 | * CFG::GetSystemModel service function | ||
| 145 | * Inputs: | ||
| 146 | * 0 : 0x00050000 | ||
| 147 | * Outputs: | ||
| 148 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 149 | * 2 : Model of the console | ||
| 150 | */ | ||
| 151 | void GetSystemModel(Service::Interface* self); | ||
| 152 | |||
| 153 | /** | ||
| 154 | * CFG::GetModelNintendo2DS service function | ||
| 155 | * Inputs: | ||
| 156 | * 0 : 0x00060000 | ||
| 157 | * Outputs: | ||
| 158 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 159 | * 2 : 0 if the system is a Nintendo 2DS, 1 otherwise | ||
| 160 | */ | ||
| 161 | void GetModelNintendo2DS(Service::Interface* self); | ||
| 162 | |||
| 163 | /** | ||
| 164 | * CFG::GetConfigInfoBlk2 service function | ||
| 165 | * Inputs: | ||
| 166 | * 0 : 0x00010082 | ||
| 167 | * 1 : Size | ||
| 168 | * 2 : Block ID | ||
| 169 | * 3 : Descriptor for the output buffer | ||
| 170 | * 4 : Output buffer pointer | ||
| 171 | * Outputs: | ||
| 172 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 173 | */ | ||
| 174 | void GetConfigInfoBlk2(Service::Interface* self); | ||
| 175 | |||
| 176 | /** | ||
| 177 | * CFG::GetConfigInfoBlk8 service function | ||
| 178 | * Inputs: | ||
| 179 | * 0 : 0x04010082 / 0x08010082 | ||
| 180 | * 1 : Size | ||
| 181 | * 2 : Block ID | ||
| 182 | * 3 : Descriptor for the output buffer | ||
| 183 | * 4 : Output buffer pointer | ||
| 184 | * Outputs: | ||
| 185 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 186 | */ | ||
| 187 | void GetConfigInfoBlk8(Service::Interface* self); | ||
| 188 | |||
| 189 | /** | ||
| 190 | * CFG::UpdateConfigNANDSavegame service function | ||
| 191 | * Inputs: | ||
| 192 | * 0 : 0x04030000 / 0x08030000 | ||
| 193 | * Outputs: | ||
| 194 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 195 | */ | ||
| 196 | void UpdateConfigNANDSavegame(Service::Interface* self); | ||
| 197 | |||
| 198 | /** | ||
| 199 | * CFG::FormatConfig service function | ||
| 200 | * Inputs: | ||
| 201 | * 0 : 0x08060000 | ||
| 202 | * Outputs: | ||
| 203 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 204 | */ | ||
| 205 | void FormatConfig(Service::Interface* self); | ||
| 206 | |||
| 43 | /// The maximum number of block entries that can exist in the config file | 207 | /// The maximum number of block entries that can exist in the config file |
| 44 | static const u32 CONFIG_FILE_MAX_BLOCK_ENTRIES = 1479; | 208 | static const u32 CONFIG_FILE_MAX_BLOCK_ENTRIES = 1479; |
| 45 | 209 | ||
diff --git a/src/core/hle/service/cfg/cfg_i.cpp b/src/core/hle/service/cfg/cfg_i.cpp index 6d1eee4e0..5aeadc084 100644 --- a/src/core/hle/service/cfg/cfg_i.cpp +++ b/src/core/hle/service/cfg/cfg_i.cpp | |||
| @@ -8,59 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service { | 9 | namespace Service { |
| 10 | namespace CFG { | 10 | namespace CFG { |
| 11 | |||
| 12 | /** | ||
| 13 | * CFG_I::GetConfigInfoBlk8 service function | ||
| 14 | * This function is called by two command headers, | ||
| 15 | * there appears to be no difference between them according to 3dbrew | ||
| 16 | * Inputs: | ||
| 17 | * 0 : 0x04010082 / 0x08010082 | ||
| 18 | * 1 : Size | ||
| 19 | * 2 : Block ID | ||
| 20 | * 3 : Descriptor for the output buffer | ||
| 21 | * 4 : Output buffer pointer | ||
| 22 | * Outputs: | ||
| 23 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 24 | */ | ||
| 25 | static void GetConfigInfoBlk8(Service::Interface* self) { | ||
| 26 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 27 | u32 size = cmd_buffer[1]; | ||
| 28 | u32 block_id = cmd_buffer[2]; | ||
| 29 | u8* data_pointer = Memory::GetPointer(cmd_buffer[4]); | ||
| 30 | |||
| 31 | if (data_pointer == nullptr) { | ||
| 32 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 33 | return; | ||
| 34 | } | ||
| 35 | |||
| 36 | cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data_pointer).raw; | ||
| 37 | } | ||
| 38 | |||
| 39 | /** | ||
| 40 | * CFG_I::UpdateConfigNANDSavegame service function | ||
| 41 | * This function is called by two command headers, | ||
| 42 | * there appears to be no difference between them according to 3dbrew | ||
| 43 | * Inputs: | ||
| 44 | * 0 : 0x04030000 / 0x08030000 | ||
| 45 | * Outputs: | ||
| 46 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 47 | */ | ||
| 48 | static void UpdateConfigNANDSavegame(Service::Interface* self) { | ||
| 49 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 50 | cmd_buffer[1] = Service::CFG::UpdateConfigNANDSavegame().raw; | ||
| 51 | } | ||
| 52 | |||
| 53 | /** | ||
| 54 | * CFG_I::FormatConfig service function | ||
| 55 | * Inputs: | ||
| 56 | * 0 : 0x08060000 | ||
| 57 | * Outputs: | ||
| 58 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 59 | */ | ||
| 60 | static void FormatConfig(Service::Interface* self) { | ||
| 61 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 62 | cmd_buffer[1] = Service::CFG::FormatConfig().raw; | ||
| 63 | } | ||
| 64 | 11 | ||
| 65 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 66 | {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, | 13 | {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, |
| @@ -68,7 +15,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 68 | {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, | 15 | {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, |
| 69 | {0x04040042, nullptr, "GetLocalFriendCodeSeedData"}, | 16 | {0x04040042, nullptr, "GetLocalFriendCodeSeedData"}, |
| 70 | {0x04050000, nullptr, "GetLocalFriendCodeSeed"}, | 17 | {0x04050000, nullptr, "GetLocalFriendCodeSeed"}, |
| 71 | {0x04060000, nullptr, "SecureInfoGetRegion"}, | 18 | {0x04060000, SecureInfoGetRegion, "SecureInfoGetRegion"}, |
| 72 | {0x04070000, nullptr, "SecureInfoGetByte101"}, | 19 | {0x04070000, nullptr, "SecureInfoGetByte101"}, |
| 73 | {0x04080042, nullptr, "SecureInfoGetSerialNo"}, | 20 | {0x04080042, nullptr, "SecureInfoGetSerialNo"}, |
| 74 | {0x04090000, nullptr, "UpdateConfigBlk00040003"}, | 21 | {0x04090000, nullptr, "UpdateConfigBlk00040003"}, |
| @@ -92,7 +39,7 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 92 | {0x08130000, nullptr, "VerifySigSecureInfo"}, | 39 | {0x08130000, nullptr, "VerifySigSecureInfo"}, |
| 93 | {0x08140042, nullptr, "SecureInfoGetData"}, | 40 | {0x08140042, nullptr, "SecureInfoGetData"}, |
| 94 | {0x08150042, nullptr, "SecureInfoGetSignature"}, | 41 | {0x08150042, nullptr, "SecureInfoGetSignature"}, |
| 95 | {0x08160000, nullptr, "SecureInfoGetRegion"}, | 42 | {0x08160000, SecureInfoGetRegion, "SecureInfoGetRegion"}, |
| 96 | {0x08170000, nullptr, "SecureInfoGetByte101"}, | 43 | {0x08170000, nullptr, "SecureInfoGetByte101"}, |
| 97 | {0x08180042, nullptr, "SecureInfoGetSerialNo"}, | 44 | {0x08180042, nullptr, "SecureInfoGetSerialNo"}, |
| 98 | }; | 45 | }; |
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp index d9a3e5d51..af4adba84 100644 --- a/src/core/hle/service/cfg/cfg_s.cpp +++ b/src/core/hle/service/cfg/cfg_s.cpp | |||
| @@ -8,68 +8,6 @@ | |||
| 8 | 8 | ||
| 9 | namespace Service { | 9 | namespace Service { |
| 10 | namespace CFG { | 10 | namespace CFG { |
| 11 | |||
| 12 | /** | ||
| 13 | * CFG_S::GetConfigInfoBlk2 service function | ||
| 14 | * Inputs: | ||
| 15 | * 0 : 0x00010082 | ||
| 16 | * 1 : Size | ||
| 17 | * 2 : Block ID | ||
| 18 | * 3 : Descriptor for the output buffer | ||
| 19 | * 4 : Output buffer pointer | ||
| 20 | * Outputs: | ||
| 21 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 22 | */ | ||
| 23 | static void GetConfigInfoBlk2(Service::Interface* self) { | ||
| 24 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 25 | u32 size = cmd_buffer[1]; | ||
| 26 | u32 block_id = cmd_buffer[2]; | ||
| 27 | u8* data_pointer = Memory::GetPointer(cmd_buffer[4]); | ||
| 28 | |||
| 29 | if (data_pointer == nullptr) { | ||
| 30 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 31 | return; | ||
| 32 | } | ||
| 33 | |||
| 34 | cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data_pointer).raw; | ||
| 35 | } | ||
| 36 | |||
| 37 | /** | ||
| 38 | * CFG_S::GetConfigInfoBlk8 service function | ||
| 39 | * Inputs: | ||
| 40 | * 0 : 0x04010082 | ||
| 41 | * 1 : Size | ||
| 42 | * 2 : Block ID | ||
| 43 | * 3 : Descriptor for the output buffer | ||
| 44 | * 4 : Output buffer pointer | ||
| 45 | * Outputs: | ||
| 46 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 47 | */ | ||
| 48 | static void GetConfigInfoBlk8(Service::Interface* self) { | ||
| 49 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 50 | u32 size = cmd_buffer[1]; | ||
| 51 | u32 block_id = cmd_buffer[2]; | ||
| 52 | u8* data_pointer = Memory::GetPointer(cmd_buffer[4]); | ||
| 53 | |||
| 54 | if (data_pointer == nullptr) { | ||
| 55 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x8, data_pointer).raw; | ||
| 60 | } | ||
| 61 | |||
| 62 | /** | ||
| 63 | * CFG_S::UpdateConfigNANDSavegame service function | ||
| 64 | * Inputs: | ||
| 65 | * 0 : 0x04030000 | ||
| 66 | * Outputs: | ||
| 67 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 68 | */ | ||
| 69 | static void UpdateConfigNANDSavegame(Service::Interface* self) { | ||
| 70 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 71 | cmd_buffer[1] = Service::CFG::UpdateConfigNANDSavegame().raw; | ||
| 72 | } | ||
| 73 | 11 | ||
| 74 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 75 | {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, | 13 | {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, |
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp index 221de9918..18939750b 100644 --- a/src/core/hle/service/cfg/cfg_u.cpp +++ b/src/core/hle/service/cfg/cfg_u.cpp | |||
| @@ -2,12 +2,6 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/file_util.h" | ||
| 6 | #include "common/logging/log.h" | ||
| 7 | #include "common/string_util.h" | ||
| 8 | |||
| 9 | #include "core/settings.h" | ||
| 10 | #include "core/file_sys/archive_systemsavedata.h" | ||
| 11 | #include "core/hle/hle.h" | 5 | #include "core/hle/hle.h" |
| 12 | #include "core/hle/service/cfg/cfg.h" | 6 | #include "core/hle/service/cfg/cfg.h" |
| 13 | #include "core/hle/service/cfg/cfg_u.h" | 7 | #include "core/hle/service/cfg/cfg_u.h" |
| @@ -15,219 +9,6 @@ | |||
| 15 | namespace Service { | 9 | namespace Service { |
| 16 | namespace CFG { | 10 | namespace CFG { |
| 17 | 11 | ||
| 18 | // TODO(Link Mauve): use a constexpr once MSVC starts supporting it. | ||
| 19 | #define C(code) ((code)[0] | ((code)[1] << 8)) | ||
| 20 | |||
| 21 | static const std::array<u16, 187> country_codes = { | ||
| 22 | 0, C("JP"), 0, 0, 0, 0, 0, 0, // 0-7 | ||
| 23 | C("AI"), C("AG"), C("AR"), C("AW"), C("BS"), C("BB"), C("BZ"), C("BO"), // 8-15 | ||
| 24 | C("BR"), C("VG"), C("CA"), C("KY"), C("CL"), C("CO"), C("CR"), C("DM"), // 16-23 | ||
| 25 | C("DO"), C("EC"), C("SV"), C("GF"), C("GD"), C("GP"), C("GT"), C("GY"), // 24-31 | ||
| 26 | C("HT"), C("HN"), C("JM"), C("MQ"), C("MX"), C("MS"), C("AN"), C("NI"), // 32-39 | ||
| 27 | C("PA"), C("PY"), C("PE"), C("KN"), C("LC"), C("VC"), C("SR"), C("TT"), // 40-47 | ||
| 28 | C("TC"), C("US"), C("UY"), C("VI"), C("VE"), 0, 0, 0, // 48-55 | ||
| 29 | 0, 0, 0, 0, 0, 0, 0, 0, // 56-63 | ||
| 30 | C("AL"), C("AU"), C("AT"), C("BE"), C("BA"), C("BW"), C("BG"), C("HR"), // 64-71 | ||
| 31 | C("CY"), C("CZ"), C("DK"), C("EE"), C("FI"), C("FR"), C("DE"), C("GR"), // 72-79 | ||
| 32 | C("HU"), C("IS"), C("IE"), C("IT"), C("LV"), C("LS"), C("LI"), C("LT"), // 80-87 | ||
| 33 | C("LU"), C("MK"), C("MT"), C("ME"), C("MZ"), C("NA"), C("NL"), C("NZ"), // 88-95 | ||
| 34 | C("NO"), C("PL"), C("PT"), C("RO"), C("RU"), C("RS"), C("SK"), C("SI"), // 96-103 | ||
| 35 | C("ZA"), C("ES"), C("SZ"), C("SE"), C("CH"), C("TR"), C("GB"), C("ZM"), // 104-111 | ||
| 36 | C("ZW"), C("AZ"), C("MR"), C("ML"), C("NE"), C("TD"), C("SD"), C("ER"), // 112-119 | ||
| 37 | C("DJ"), C("SO"), C("AD"), C("GI"), C("GG"), C("IM"), C("JE"), C("MC"), // 120-127 | ||
| 38 | C("TW"), 0, 0, 0, 0, 0, 0, 0, // 128-135 | ||
| 39 | C("KR"), 0, 0, 0, 0, 0, 0, 0, // 136-143 | ||
| 40 | C("HK"), C("MO"), 0, 0, 0, 0, 0, 0, // 144-151 | ||
| 41 | C("ID"), C("SG"), C("TH"), C("PH"), C("MY"), 0, 0, 0, // 152-159 | ||
| 42 | C("CN"), 0, 0, 0, 0, 0, 0, 0, // 160-167 | ||
| 43 | C("AE"), C("IN"), C("EG"), C("OM"), C("QA"), C("KW"), C("SA"), C("SY"), // 168-175 | ||
| 44 | C("BH"), C("JO"), 0, 0, 0, 0, 0, 0, // 176-183 | ||
| 45 | C("SM"), C("VA"), C("BM") // 184-186 | ||
| 46 | }; | ||
| 47 | |||
| 48 | #undef C | ||
| 49 | |||
| 50 | /** | ||
| 51 | * CFG_User::GetCountryCodeString service function | ||
| 52 | * Inputs: | ||
| 53 | * 1 : Country Code ID | ||
| 54 | * Outputs: | ||
| 55 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 56 | * 2 : Country's 2-char string | ||
| 57 | */ | ||
| 58 | static void GetCountryCodeString(Service::Interface* self) { | ||
| 59 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 60 | u32 country_code_id = cmd_buffer[1]; | ||
| 61 | |||
| 62 | if (country_code_id >= country_codes.size() || 0 == country_codes[country_code_id]) { | ||
| 63 | LOG_ERROR(Service_CFG, "requested country code id=%d is invalid", country_code_id); | ||
| 64 | cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw; | ||
| 65 | return; | ||
| 66 | } | ||
| 67 | |||
| 68 | cmd_buffer[1] = 0; | ||
| 69 | cmd_buffer[2] = country_codes[country_code_id]; | ||
| 70 | } | ||
| 71 | |||
| 72 | /** | ||
| 73 | * CFG_User::GetCountryCodeID service function | ||
| 74 | * Inputs: | ||
| 75 | * 1 : Country Code 2-char string | ||
| 76 | * Outputs: | ||
| 77 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 78 | * 2 : Country Code ID | ||
| 79 | */ | ||
| 80 | static void GetCountryCodeID(Service::Interface* self) { | ||
| 81 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 82 | u16 country_code = cmd_buffer[1]; | ||
| 83 | u16 country_code_id = 0; | ||
| 84 | |||
| 85 | // The following algorithm will fail if the first country code isn't 0. | ||
| 86 | DEBUG_ASSERT(country_codes[0] == 0); | ||
| 87 | |||
| 88 | for (u16 id = 0; id < country_codes.size(); ++id) { | ||
| 89 | if (country_codes[id] == country_code) { | ||
| 90 | country_code_id = id; | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | if (0 == country_code_id) { | ||
| 96 | LOG_ERROR(Service_CFG, "requested country code name=%c%c is invalid", country_code & 0xff, country_code >> 8); | ||
| 97 | cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw; | ||
| 98 | cmd_buffer[2] = 0xFFFF; | ||
| 99 | return; | ||
| 100 | } | ||
| 101 | |||
| 102 | cmd_buffer[1] = 0; | ||
| 103 | cmd_buffer[2] = country_code_id; | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * CFG_User::GetConfigInfoBlk2 service function | ||
| 108 | * Inputs: | ||
| 109 | * 0 : 0x00010082 | ||
| 110 | * 1 : Size | ||
| 111 | * 2 : Block ID | ||
| 112 | * 3 : Descriptor for the output buffer | ||
| 113 | * 4 : Output buffer pointer | ||
| 114 | * Outputs: | ||
| 115 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 116 | */ | ||
| 117 | static void GetConfigInfoBlk2(Service::Interface* self) { | ||
| 118 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 119 | u32 size = cmd_buffer[1]; | ||
| 120 | u32 block_id = cmd_buffer[2]; | ||
| 121 | u8* data_pointer = Memory::GetPointer(cmd_buffer[4]); | ||
| 122 | |||
| 123 | if (data_pointer == nullptr) { | ||
| 124 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | |||
| 128 | cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(block_id, size, 0x2, data_pointer).raw; | ||
| 129 | } | ||
| 130 | |||
| 131 | /** | ||
| 132 | * CFG_User::SecureInfoGetRegion service function | ||
| 133 | * Inputs: | ||
| 134 | * 1 : None | ||
| 135 | * Outputs: | ||
| 136 | * 0 : Result Header code | ||
| 137 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 138 | * 2 : Region value loaded from SecureInfo offset 0x100 | ||
| 139 | */ | ||
| 140 | static void SecureInfoGetRegion(Service::Interface* self) { | ||
| 141 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 142 | |||
| 143 | cmd_buffer[1] = RESULT_SUCCESS.raw; // No Error | ||
| 144 | cmd_buffer[2] = Settings::values.region_value; | ||
| 145 | } | ||
| 146 | |||
| 147 | /** | ||
| 148 | * CFG_User::GenHashConsoleUnique service function | ||
| 149 | * Inputs: | ||
| 150 | * 1 : 20 bit application ID salt | ||
| 151 | * Outputs: | ||
| 152 | * 0 : Result Header code | ||
| 153 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 154 | * 2 : Hash/"ID" lower word | ||
| 155 | * 3 : Hash/"ID" upper word | ||
| 156 | */ | ||
| 157 | static void GenHashConsoleUnique(Service::Interface* self) { | ||
| 158 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 159 | u32 app_id_salt = cmd_buffer[1]; | ||
| 160 | |||
| 161 | cmd_buffer[1] = RESULT_SUCCESS.raw; // No Error | ||
| 162 | cmd_buffer[2] = 0x33646D6F ^ (app_id_salt & 0xFFFFF); // 3dmoo hash | ||
| 163 | cmd_buffer[3] = 0x6F534841 ^ (app_id_salt & 0xFFFFF); | ||
| 164 | |||
| 165 | LOG_WARNING(Service_CFG, "(STUBBED) called app_id_salt=0x%08X", app_id_salt); | ||
| 166 | } | ||
| 167 | |||
| 168 | /** | ||
| 169 | * CFG_User::GetRegionCanadaUSA service function | ||
| 170 | * Inputs: | ||
| 171 | * 1 : None | ||
| 172 | * Outputs: | ||
| 173 | * 0 : Result Header code | ||
| 174 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 175 | * 2 : Output value | ||
| 176 | */ | ||
| 177 | static void GetRegionCanadaUSA(Service::Interface* self) { | ||
| 178 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 179 | |||
| 180 | cmd_buffer[1] = RESULT_SUCCESS.raw; // No Error | ||
| 181 | |||
| 182 | u8 canada_or_usa = 1; | ||
| 183 | if (canada_or_usa == Settings::values.region_value) { | ||
| 184 | cmd_buffer[2] = 1; | ||
| 185 | } else { | ||
| 186 | cmd_buffer[2] = 0; | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | /** | ||
| 191 | * CFG_User::GetSystemModel service function | ||
| 192 | * Inputs: | ||
| 193 | * 0 : 0x00050000 | ||
| 194 | * Outputs: | ||
| 195 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 196 | * 2 : Model of the console | ||
| 197 | */ | ||
| 198 | static void GetSystemModel(Service::Interface* self) { | ||
| 199 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 200 | u32 data; | ||
| 201 | |||
| 202 | // TODO(Subv): Find out the correct error codes | ||
| 203 | cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8, | ||
| 204 | reinterpret_cast<u8*>(&data)).raw; | ||
| 205 | cmd_buffer[2] = data & 0xFF; | ||
| 206 | } | ||
| 207 | |||
| 208 | /** | ||
| 209 | * CFG_User::GetModelNintendo2DS service function | ||
| 210 | * Inputs: | ||
| 211 | * 0 : 0x00060000 | ||
| 212 | * Outputs: | ||
| 213 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 214 | * 2 : 0 if the system is a Nintendo 2DS, 1 otherwise | ||
| 215 | */ | ||
| 216 | static void GetModelNintendo2DS(Service::Interface* self) { | ||
| 217 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 218 | u32 data; | ||
| 219 | |||
| 220 | // TODO(Subv): Find out the correct error codes | ||
| 221 | cmd_buffer[1] = Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8, | ||
| 222 | reinterpret_cast<u8*>(&data)).raw; | ||
| 223 | |||
| 224 | u8 model = data & 0xFF; | ||
| 225 | if (model == Service::CFG::NINTENDO_2DS) | ||
| 226 | cmd_buffer[2] = 0; | ||
| 227 | else | ||
| 228 | cmd_buffer[2] = 1; | ||
| 229 | } | ||
| 230 | |||
| 231 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 232 | {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, | 13 | {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, |
| 233 | {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"}, | 14 | {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"}, |