diff options
| author | 2014-12-18 23:35:24 -0500 | |
|---|---|---|
| committer | 2014-12-21 16:38:54 -0500 | |
| commit | fa3d72ab3e5ba8b3e8dccdb1d3bd9b976dbc28e2 (patch) | |
| tree | 282a7eb7c7a28c77760017c1d2164b3e2f3a40f7 /src/core | |
| parent | Merge pull request #291 from purpasmart96/license (diff) | |
| download | yuzu-fa3d72ab3e5ba8b3e8dccdb1d3bd9b976dbc28e2.tar.gz yuzu-fa3d72ab3e5ba8b3e8dccdb1d3bd9b976dbc28e2.tar.xz yuzu-fa3d72ab3e5ba8b3e8dccdb1d3bd9b976dbc28e2.zip | |
CFG: Implemented the GetConfigInfoBlk2 function.
Added a "config" file to the CFG process service (CFG:U), and added a few default blocks to it.
Implemented GetSystemModel and GetModelNintendo2DS
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/file_sys/archive_backend.h | 5 | ||||
| -rw-r--r-- | src/core/file_sys/archive_systemsavedata.cpp | 5 | ||||
| -rw-r--r-- | src/core/file_sys/archive_systemsavedata.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/cfg_u.cpp | 191 | ||||
| -rw-r--r-- | src/core/hle/service/fs/archive.cpp | 9 |
5 files changed, 197 insertions, 15 deletions
diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index eb1fdaa1f..e2979be17 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h | |||
| @@ -45,6 +45,11 @@ public: | |||
| 45 | { | 45 | { |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | Path(const char* path): | ||
| 49 | type(Char), string(path) | ||
| 50 | { | ||
| 51 | } | ||
| 52 | |||
| 48 | Path(LowPathType type, u32 size, u32 pointer): | 53 | Path(LowPathType type, u32 size, u32 pointer): |
| 49 | type(type) | 54 | type(type) |
| 50 | { | 55 | { |
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp index 5da1ec946..392c3cd39 100644 --- a/src/core/file_sys/archive_systemsavedata.cpp +++ b/src/core/file_sys/archive_systemsavedata.cpp | |||
| @@ -16,8 +16,9 @@ | |||
| 16 | 16 | ||
| 17 | namespace FileSys { | 17 | namespace FileSys { |
| 18 | 18 | ||
| 19 | Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point) | 19 | Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point, u64 save_id) |
| 20 | : DiskArchive(mount_point) { | 20 | : DiskArchive(Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), |
| 21 | static_cast<u32>(save_id & 0xFFFFFFFF), static_cast<u32>((save_id >> 31) & 0xFFFFFFFF))) { | ||
| 21 | LOG_INFO(Service_FS, "Directory %s set as SystemSaveData.", this->mount_point.c_str()); | 22 | LOG_INFO(Service_FS, "Directory %s set as SystemSaveData.", this->mount_point.c_str()); |
| 22 | } | 23 | } |
| 23 | 24 | ||
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h index c3ebb7c99..443e27091 100644 --- a/src/core/file_sys/archive_systemsavedata.h +++ b/src/core/file_sys/archive_systemsavedata.h | |||
| @@ -19,7 +19,7 @@ namespace FileSys { | |||
| 19 | /// specifically nand:/data/<ID0>/sysdata/<SaveID-Low>/<SaveID-High> | 19 | /// specifically nand:/data/<ID0>/sysdata/<SaveID-Low>/<SaveID-High> |
| 20 | class Archive_SystemSaveData final : public DiskArchive { | 20 | class Archive_SystemSaveData final : public DiskArchive { |
| 21 | public: | 21 | public: |
| 22 | Archive_SystemSaveData(const std::string& mount_point); | 22 | Archive_SystemSaveData(const std::string& mount_point, u64 save_id); |
| 23 | 23 | ||
| 24 | /** | 24 | /** |
| 25 | * Initialize the archive. | 25 | * Initialize the archive. |
diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp index 6fcd1d7f3..e6c9ce1fa 100644 --- a/src/core/hle/service/cfg_u.cpp +++ b/src/core/hle/service/cfg_u.cpp | |||
| @@ -2,7 +2,9 @@ | |||
| 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" | ||
| 5 | #include "common/log.h" | 6 | #include "common/log.h" |
| 7 | #include "core/file_sys/archive_systemsavedata.h" | ||
| 6 | #include "core/hle/hle.h" | 8 | #include "core/hle/hle.h" |
| 7 | #include "core/hle/service/cfg_u.h" | 9 | #include "core/hle/service/cfg_u.h" |
| 8 | 10 | ||
| @@ -11,6 +13,19 @@ | |||
| 11 | 13 | ||
| 12 | namespace CFG_U { | 14 | namespace CFG_U { |
| 13 | 15 | ||
| 16 | static std::unique_ptr<FileSys::Archive_SystemSaveData> cfg_system_save_data; | ||
| 17 | static const u64 CFG_SAVE_ID = 0x00010017; | ||
| 18 | static const u64 CONSOLE_UNIQUE_ID = 0xDEADC0DE; | ||
| 19 | static const char CONSOLE_USERNAME[0x1C] = "THIS IS CITRAAAAAAAAAAAAAA"; | ||
| 20 | |||
| 21 | enum SystemModel { | ||
| 22 | NINTENDO_3DS, | ||
| 23 | NINTENDO_3DS_XL, | ||
| 24 | NEW_NINTENDO_3DS, | ||
| 25 | NINTENDO_2DS, | ||
| 26 | NEW_NINTENDO_3DS_XL | ||
| 27 | }; | ||
| 28 | |||
| 14 | // TODO(Link Mauve): use a constexpr once MSVC starts supporting it. | 29 | // TODO(Link Mauve): use a constexpr once MSVC starts supporting it. |
| 15 | #define C(code) ((code)[0] | ((code)[1] << 8)) | 30 | #define C(code) ((code)[0] | ((code)[1] << 8)) |
| 16 | 31 | ||
| @@ -99,13 +114,137 @@ static void GetCountryCodeID(Service::Interface* self) { | |||
| 99 | cmd_buffer[2] = country_code_id; | 114 | cmd_buffer[2] = country_code_id; |
| 100 | } | 115 | } |
| 101 | 116 | ||
| 117 | /// Block header in the config savedata file | ||
| 118 | struct SaveConfigBlockEntry { | ||
| 119 | u32 block_id; | ||
| 120 | u32 offset_or_data; | ||
| 121 | u16 size; | ||
| 122 | u16 flags; | ||
| 123 | }; | ||
| 124 | |||
| 125 | /// The header of the config savedata file, | ||
| 126 | /// contains information about the blocks in the file | ||
| 127 | struct SaveFileConfig { | ||
| 128 | u16 total_entries; | ||
| 129 | u16 data_entries_offset; | ||
| 130 | SaveConfigBlockEntry block_entries[1479]; | ||
| 131 | }; | ||
| 132 | |||
| 133 | /* Reads a block with the specified id and flag from the Config savegame file | ||
| 134 | * and writes the output to output. | ||
| 135 | * The input size must match exactly the size of the requested block | ||
| 136 | * TODO(Subv): This should actually be in some file common to the CFG process | ||
| 137 | * @param block_id The id of the block we want to read | ||
| 138 | * @param size The size of the block we want to read | ||
| 139 | * @param flag The requested block must have this flag set | ||
| 140 | * @param output A pointer where we will write the read data | ||
| 141 | * @returns ResultCode indicating the result of the operation, 0 on success | ||
| 142 | */ | ||
| 143 | ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { | ||
| 144 | FileSys::Mode mode; | ||
| 145 | mode.hex = 0; | ||
| 146 | mode.read_flag = 1; | ||
| 147 | FileSys::Path path("config"); | ||
| 148 | auto file = cfg_system_save_data->OpenFile(path, mode); | ||
| 149 | _dbg_assert_msg_(Service_CFG, file != nullptr, "Could not open the CFG service config file"); | ||
| 150 | SaveFileConfig config; | ||
| 151 | size_t read = file->Read(0, sizeof(SaveFileConfig), reinterpret_cast<u8*>(&config)); | ||
| 152 | |||
| 153 | if (read != sizeof(SaveFileConfig)) { | ||
| 154 | LOG_CRITICAL(Service_CFG, "The config savefile is corrupted"); | ||
| 155 | return ResultCode(-1); // TODO(Subv): Find the correct error code | ||
| 156 | } | ||
| 157 | |||
| 158 | auto itr = std::find_if(std::begin(config.block_entries), std::end(config.block_entries), | ||
| 159 | [&](SaveConfigBlockEntry const& entry) { | ||
| 160 | return entry.block_id == block_id && entry.size == size && (entry.flags & flag); | ||
| 161 | }); | ||
| 162 | |||
| 163 | if (itr == std::end(config.block_entries)) { | ||
| 164 | LOG_TRACE(Service_CFG, "Config block %u with size %u and flags %u not found", block_id, size, flag); | ||
| 165 | return ResultCode(-1); // TODO(Subv): Find the correct error code | ||
| 166 | } | ||
| 167 | |||
| 168 | // The data is located in the block header itself if the size is less than 4 bytes | ||
| 169 | if (itr->size <= 4) { | ||
| 170 | memcpy(output, &itr->offset_or_data, itr->size); | ||
| 171 | } else { | ||
| 172 | size_t data_read = file->Read(itr->offset_or_data, itr->size, output); | ||
| 173 | if (data_read != itr->size) { | ||
| 174 | LOG_CRITICAL(Service_CFG, "The config savefile is corrupted"); | ||
| 175 | return ResultCode(-1); // TODO(Subv): Find the correct error code | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | return RESULT_SUCCESS; | ||
| 180 | } | ||
| 181 | |||
| 182 | /** | ||
| 183 | * CFG_User::GetConfigInfoBlk2 service function | ||
| 184 | * Inputs: | ||
| 185 | * 1 : Size | ||
| 186 | * 2 : Block ID | ||
| 187 | * 3 : Descriptor for the output buffer | ||
| 188 | * 4 : Output buffer pointer | ||
| 189 | * Outputs: | ||
| 190 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 191 | */ | ||
| 192 | static void GetConfigInfoBlk2(Service::Interface* self) { | ||
| 193 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 194 | u32 size = cmd_buffer[1]; | ||
| 195 | u32 block_id = cmd_buffer[2]; | ||
| 196 | u8* data_pointer = Memory::GetPointer(cmd_buffer[4]); | ||
| 197 | |||
| 198 | if (data_pointer == nullptr) { | ||
| 199 | cmd_buffer[1] = -1; // TODO(Subv): Find the right error code | ||
| 200 | return; | ||
| 201 | } | ||
| 202 | |||
| 203 | cmd_buffer[1] = GetConfigInfoBlock(block_id, size, 0x2, data_pointer).raw; | ||
| 204 | } | ||
| 205 | |||
| 206 | /** | ||
| 207 | * CFG_User::GetSystemModel service function | ||
| 208 | * Outputs: | ||
| 209 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 210 | * 2 : Model of the console | ||
| 211 | */ | ||
| 212 | static void GetSystemModel(Service::Interface* self) { | ||
| 213 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 214 | u32 data; | ||
| 215 | |||
| 216 | cmd_buffer[1] = GetConfigInfoBlock(0x000F0004, 4, 0x8, | ||
| 217 | reinterpret_cast<u8*>(&data)).raw; // TODO(Subv): Find out the correct error codes | ||
| 218 | cmd_buffer[2] = data & 0xFF; | ||
| 219 | } | ||
| 220 | |||
| 221 | /** | ||
| 222 | * CFG_User::GetModelNintendo2DS service function | ||
| 223 | * Outputs: | ||
| 224 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 225 | * 2 : 0 if the system is a Nintendo 2DS, 1 otherwise | ||
| 226 | */ | ||
| 227 | static void GetModelNintendo2DS(Service::Interface* self) { | ||
| 228 | u32* cmd_buffer = Kernel::GetCommandBuffer(); | ||
| 229 | u32 data; | ||
| 230 | |||
| 231 | cmd_buffer[1] = GetConfigInfoBlock(0x000F0004, 4, 0x8, | ||
| 232 | reinterpret_cast<u8*>(&data)).raw; // TODO(Subv): Find out the correct error codes | ||
| 233 | |||
| 234 | u8 model = data & 0xFF; | ||
| 235 | if (model == NINTENDO_2DS) | ||
| 236 | cmd_buffer[2] = 0; | ||
| 237 | else | ||
| 238 | cmd_buffer[2] = 1; | ||
| 239 | } | ||
| 240 | |||
| 102 | const Interface::FunctionInfo FunctionTable[] = { | 241 | const Interface::FunctionInfo FunctionTable[] = { |
| 103 | {0x00010082, nullptr, "GetConfigInfoBlk2"}, | 242 | {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, |
| 104 | {0x00020000, nullptr, "SecureInfoGetRegion"}, | 243 | {0x00020000, nullptr, "SecureInfoGetRegion"}, |
| 105 | {0x00030000, nullptr, "GenHashConsoleUnique"}, | 244 | {0x00030000, nullptr, "GenHashConsoleUnique"}, |
| 106 | {0x00040000, nullptr, "GetRegionCanadaUSA"}, | 245 | {0x00040000, nullptr, "GetRegionCanadaUSA"}, |
| 107 | {0x00050000, nullptr, "GetSystemModel"}, | 246 | {0x00050000, GetSystemModel, "GetSystemModel"}, |
| 108 | {0x00060000, nullptr, "GetModelNintendo2DS"}, | 247 | {0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"}, |
| 109 | {0x00070040, nullptr, "unknown"}, | 248 | {0x00070040, nullptr, "unknown"}, |
| 110 | {0x00080080, nullptr, "unknown"}, | 249 | {0x00080080, nullptr, "unknown"}, |
| 111 | {0x00090040, GetCountryCodeString, "GetCountryCodeString"}, | 250 | {0x00090040, GetCountryCodeString, "GetCountryCodeString"}, |
| @@ -116,6 +255,52 @@ const Interface::FunctionInfo FunctionTable[] = { | |||
| 116 | 255 | ||
| 117 | Interface::Interface() { | 256 | Interface::Interface() { |
| 118 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); | 257 | Register(FunctionTable, ARRAY_SIZE(FunctionTable)); |
| 258 | // TODO(Subv): In the future we should use the FS service to query this archive, | ||
| 259 | // currently it is not possible because you can only have one open archive of the same type at any time | ||
| 260 | std::string syssavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX); | ||
| 261 | cfg_system_save_data = std::make_unique<FileSys::Archive_SystemSaveData>(syssavedata_directory, | ||
| 262 | CFG_SAVE_ID); | ||
| 263 | if (!cfg_system_save_data->Initialize()) { | ||
| 264 | LOG_CRITICAL(Service_CFG, "Could not initialize SystemSaveData archive for the CFG:U service"); | ||
| 265 | return; | ||
| 266 | } | ||
| 267 | |||
| 268 | // Try to open the file in read-only mode to check its existence | ||
| 269 | FileSys::Mode mode; | ||
| 270 | mode.hex = 0; | ||
| 271 | mode.read_flag = 1; | ||
| 272 | FileSys::Path path("config"); | ||
| 273 | auto file = cfg_system_save_data->OpenFile(path, mode); | ||
| 274 | |||
| 275 | // Don't do anything if the file already exists | ||
| 276 | if (file != nullptr) | ||
| 277 | return; | ||
| 278 | |||
| 279 | mode.create_flag = 1; | ||
| 280 | mode.write_flag = 1; | ||
| 281 | mode.read_flag = 0; | ||
| 282 | // Re-open the file in write-create mode | ||
| 283 | file = cfg_system_save_data->OpenFile(path, mode); | ||
| 284 | |||
| 285 | // Setup the default config file data header | ||
| 286 | SaveFileConfig config = { 3, 0, {} }; | ||
| 287 | u32 offset = sizeof(SaveFileConfig); | ||
| 288 | // Console-unique ID | ||
| 289 | config.block_entries[0] = { 0x00090001, offset, 0x8, 0xE }; | ||
| 290 | offset += 0x8; | ||
| 291 | // Username | ||
| 292 | config.block_entries[1] = { 0x000A0000, offset, 0x1C, 0xE }; | ||
| 293 | offset += 0x1C; | ||
| 294 | // System Model (Nintendo 3DS XL) | ||
| 295 | config.block_entries[2] = { 0x000F0004, NINTENDO_3DS_XL, 0x4, 0x8 }; | ||
| 296 | |||
| 297 | // Write the config file data header to the config file | ||
| 298 | file->Write(0, sizeof(SaveFileConfig), 1, reinterpret_cast<u8*>(&config)); | ||
| 299 | // Write the data itself | ||
| 300 | file->Write(config.block_entries[0].offset_or_data, 0x8, 1, | ||
| 301 | reinterpret_cast<u8 const*>(&CONSOLE_UNIQUE_ID)); | ||
| 302 | file->Write(config.block_entries[1].offset_or_data, 0x1C, 1, | ||
| 303 | reinterpret_cast<u8 const*>(CONSOLE_USERNAME)); | ||
| 119 | } | 304 | } |
| 120 | 305 | ||
| 121 | Interface::~Interface() { | 306 | Interface::~Interface() { |
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index e2a59a069..98db02f15 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp | |||
| @@ -428,15 +428,6 @@ void ArchiveInit() { | |||
| 428 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); | 428 | CreateArchive(std::move(sdmc_archive), ArchiveIdCode::SDMC); |
| 429 | else | 429 | else |
| 430 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); | 430 | LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); |
| 431 | |||
| 432 | std::string systemsavedata_directory = FileUtil::GetUserPath(D_SYSSAVEDATA_IDX); | ||
| 433 | auto systemsavedata_archive = Common::make_unique<FileSys::Archive_SDMC>(systemsavedata_directory); | ||
| 434 | if (systemsavedata_archive->Initialize()) { | ||
| 435 | CreateArchive(std::move(systemsavedata_archive), ArchiveIdCode::SystemSaveData); | ||
| 436 | } else { | ||
| 437 | LOG_ERROR(Service_FS, "Can't instantiate SystemSaveData archive with path %s", | ||
| 438 | systemsavedata_directory.c_str()); | ||
| 439 | } | ||
| 440 | } | 431 | } |
| 441 | 432 | ||
| 442 | /// Shutdown archives | 433 | /// Shutdown archives |