summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Subv2014-12-19 15:30:25 -0500
committerGravatar Subv2014-12-21 16:38:59 -0500
commit4cd21b43c1e28933898c4a2e829555efe22ff12e (patch)
treebff4da5013682afa238f56efdc6ffd0ff9e827bf
parentCFG:U: Add some data to the 0x00050005 config block. (diff)
downloadyuzu-4cd21b43c1e28933898c4a2e829555efe22ff12e.tar.gz
yuzu-4cd21b43c1e28933898c4a2e829555efe22ff12e.tar.xz
yuzu-4cd21b43c1e28933898c4a2e829555efe22ff12e.zip
CFG: Refactored how the config file works.
It is now kept in memory as per 3dbrew, all updates happen on memory, then they can be saved using UpdateConfigNANDSavegame.
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp2
-rw-r--r--src/core/hle/service/cfg_u.cpp181
2 files changed, 127 insertions, 56 deletions
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 392c3cd39..b942864b2 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -18,7 +18,7 @@ namespace FileSys {
18 18
19Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point, u64 save_id) 19Archive_SystemSaveData::Archive_SystemSaveData(const std::string& mount_point, u64 save_id)
20 : DiskArchive(Common::StringFromFormat("%s%08X/%08X/", mount_point.c_str(), 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 static_cast<u32>(save_id & 0xFFFFFFFF), static_cast<u32>((save_id >> 32) & 0xFFFFFFFF))) {
22 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());
23} 23}
24 24
diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp
index 771575e29..827399cf9 100644
--- a/src/core/hle/service/cfg_u.cpp
+++ b/src/core/hle/service/cfg_u.cpp
@@ -13,9 +13,20 @@
13 13
14namespace CFG_U { 14namespace CFG_U {
15 15
16enum SystemModel {
17 NINTENDO_3DS,
18 NINTENDO_3DS_XL,
19 NEW_NINTENDO_3DS,
20 NINTENDO_2DS,
21 NEW_NINTENDO_3DS_XL
22};
23
16static std::unique_ptr<FileSys::Archive_SystemSaveData> cfg_system_save_data; 24static std::unique_ptr<FileSys::Archive_SystemSaveData> cfg_system_save_data;
17static const u64 CFG_SAVE_ID = 0x00010017; 25static const u64 CFG_SAVE_ID = 0x00010017;
18static const u64 CONSOLE_UNIQUE_ID = 0xDEADC0DE; 26static const u64 CONSOLE_UNIQUE_ID = 0xDEADC0DE;
27static const u32 CONSOLE_MODEL = NINTENDO_3DS_XL;
28static const u32 CONFIG_SAVEFILE_SIZE = 0x8000;
29static std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer = { };
19 30
20/// TODO(Subv): Find out what this actually is 31/// TODO(Subv): Find out what this actually is
21/// Thanks Normmatt for providing this information 32/// Thanks Normmatt for providing this information
@@ -24,14 +35,6 @@ static const u8 STEREO_CAMERA_SETTINGS[32] = {
24 0x00, 0x00, 0x20, 0x41, 0x00, 0x00, 0xA0, 0x40, 0xEC, 0x51, 0x5E, 0x42, 0x5C, 0x8F, 0xAC, 0x41 35 0x00, 0x00, 0x20, 0x41, 0x00, 0x00, 0xA0, 0x40, 0xEC, 0x51, 0x5E, 0x42, 0x5C, 0x8F, 0xAC, 0x41
25}; 36};
26 37
27enum SystemModel {
28 NINTENDO_3DS,
29 NINTENDO_3DS_XL,
30 NEW_NINTENDO_3DS,
31 NINTENDO_2DS,
32 NEW_NINTENDO_3DS_XL
33};
34
35// TODO(Link Mauve): use a constexpr once MSVC starts supporting it. 38// TODO(Link Mauve): use a constexpr once MSVC starts supporting it.
36#define C(code) ((code)[0] | ((code)[1] << 8)) 39#define C(code) ((code)[0] | ((code)[1] << 8))
37 40
@@ -134,9 +137,11 @@ struct SaveFileConfig {
134 u16 total_entries; 137 u16 total_entries;
135 u16 data_entries_offset; 138 u16 data_entries_offset;
136 SaveConfigBlockEntry block_entries[1479]; 139 SaveConfigBlockEntry block_entries[1479];
140 u32 unknown;
137}; 141};
138 142
139/* Reads a block with the specified id and flag from the Config savegame file 143/**
144 * Reads a block with the specified id and flag from the Config savegame buffer
140 * and writes the output to output. 145 * and writes the output to output.
141 * The input size must match exactly the size of the requested block 146 * The input size must match exactly the size of the requested block
142 * TODO(Subv): This should actually be in some file common to the CFG process 147 * TODO(Subv): This should actually be in some file common to the CFG process
@@ -147,41 +152,128 @@ struct SaveFileConfig {
147 * @returns ResultCode indicating the result of the operation, 0 on success 152 * @returns ResultCode indicating the result of the operation, 0 on success
148 */ 153 */
149ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) { 154ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) {
150 FileSys::Mode mode; 155 // Read the header
151 mode.hex = 0; 156 SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
152 mode.read_flag = 1;
153 FileSys::Path path("config");
154 auto file = cfg_system_save_data->OpenFile(path, mode);
155 _dbg_assert_msg_(Service_CFG, file != nullptr, "Could not open the CFG service config file");
156 SaveFileConfig config;
157 size_t read = file->Read(0, sizeof(SaveFileConfig), reinterpret_cast<u8*>(&config));
158 157
159 if (read != sizeof(SaveFileConfig)) { 158 auto itr = std::find_if(std::begin(config->block_entries), std::end(config->block_entries),
160 LOG_CRITICAL(Service_CFG, "The config savefile is corrupted");
161 return ResultCode(-1); // TODO(Subv): Find the correct error code
162 }
163
164 auto itr = std::find_if(std::begin(config.block_entries), std::end(config.block_entries),
165 [&](SaveConfigBlockEntry const& entry) { 159 [&](SaveConfigBlockEntry const& entry) {
166 return entry.block_id == block_id && entry.size == size && (entry.flags & flag); 160 return entry.block_id == block_id && entry.size == size && (entry.flags & flag);
167 }); 161 });
168 162
169 if (itr == std::end(config.block_entries)) { 163 if (itr == std::end(config->block_entries)) {
170 LOG_TRACE(Service_CFG, "Config block %u with size %u and flags %u not found", block_id, size, flag); 164 LOG_ERROR(Service_CFG, "Config block %u with size %u and flags %u not found", block_id, size, flag);
171 return ResultCode(-1); // TODO(Subv): Find the correct error code 165 return ResultCode(-1); // TODO(Subv): Find the correct error code
172 } 166 }
173 167
174 // The data is located in the block header itself if the size is less than 4 bytes 168 // The data is located in the block header itself if the size is less than 4 bytes
175 if (itr->size <= 4) { 169 if (itr->size <= 4)
176 memcpy(output, &itr->offset_or_data, itr->size); 170 memcpy(output, &itr->offset_or_data, itr->size);
177 } else { 171 else
178 size_t data_read = file->Read(itr->offset_or_data, itr->size, output); 172 memcpy(output, &cfg_config_file_buffer[config->data_entries_offset + itr->offset_or_data], itr->size);
179 if (data_read != itr->size) { 173
180 LOG_CRITICAL(Service_CFG, "The config savefile is corrupted"); 174 return RESULT_SUCCESS;
181 return ResultCode(-1); // TODO(Subv): Find the correct error code 175}
176
177/**
178 * Creates a block with the specified id and writes the input data to the cfg savegame buffer in memory.
179 * The config savegame file in the filesystem is not updated.
180 * TODO(Subv): This should actually be in some file common to the CFG process
181 * @param block_id The id of the block we want to create
182 * @param size The size of the block we want to create
183 * @param flag The flags of the new block
184 * @param data A pointer containing the data we will write to the new block
185 * @returns ResultCode indicating the result of the operation, 0 on success
186 */
187ResultCode CreateConfigInfoBlk(u32 block_id, u32 size, u32 flags, u8 const* data) {
188 SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
189 // Insert the block header with offset 0 for now
190 config->block_entries[config->total_entries] = { block_id, 0, size, flags };
191 if (size > 4) {
192 s32 total_entries = config->total_entries - 1;
193 u32 offset = 0;
194 // Perform a search to locate the next offset for the new data
195 while (total_entries >= 0) {
196 // Ignore the blocks that don't have a separate data offset
197 if (config->block_entries[total_entries].size <= 4) {
198 --total_entries;
199 continue;
200 }
201
202 offset = config->block_entries[total_entries].offset_or_data +
203 config->block_entries[total_entries].size;
204 break;
182 } 205 }
206
207 config->block_entries[config->total_entries].offset_or_data = offset;
208
209 // Write the data at the new offset
210 memcpy(&cfg_config_file_buffer[config->data_entries_offset + offset], data, size);
211 } else {
212 // The offset_or_data field in the header contains the data itself if it's 4 bytes or less
213 memcpy(&config->block_entries[config->total_entries].offset_or_data, data, size);
183 } 214 }
184 215
216 ++config->total_entries;
217 return RESULT_SUCCESS;
218}
219
220/**
221 * Deletes the config savegame file from the filesystem, the buffer in memory is not affected
222 * TODO(Subv): This should actually be in some file common to the CFG process
223 * @returns ResultCode indicating the result of the operation, 0 on success
224 */
225ResultCode DeleteConfigNANDSaveFile() {
226 FileSys::Path path("config");
227 if (cfg_system_save_data->DeleteFile(path))
228 return RESULT_SUCCESS;
229 return ResultCode(-1); // TODO(Subv): Find the right error code
230}
231
232/**
233 * Writes the config savegame memory buffer to the config savegame file in the filesystem
234 * TODO(Subv): This should actually be in some file common to the CFG process
235 * @returns ResultCode indicating the result of the operation, 0 on success
236 */
237ResultCode UpdateConfigNANDSavegame() {
238 FileSys::Mode mode;
239 mode.hex = 0;
240 mode.write_flag = 1;
241 mode.create_flag = 1;
242 FileSys::Path path("config");
243 auto file = cfg_system_save_data->OpenFile(path, mode);
244 _dbg_assert_msg_(Service_CFG, file != nullptr, "could not open file");
245 file->Write(0, CONFIG_SAVEFILE_SIZE, 1, cfg_config_file_buffer.data());
246 return RESULT_SUCCESS;
247}
248
249/**
250 * Re-creates the config savegame file in memory and the filesystem with the default blocks
251 * TODO(Subv): This should actually be in some file common to the CFG process
252 * @returns ResultCode indicating the result of the operation, 0 on success
253 */
254ResultCode FormatConfig() {
255 ResultCode res = DeleteConfigNANDSaveFile();
256 if (!res.IsSuccess())
257 return res;
258 // Delete the old data
259 std::fill(cfg_config_file_buffer.begin(), cfg_config_file_buffer.end(), 0);
260 // Create the header
261 SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
262 config->data_entries_offset = 0x455C;
263 // Insert the default blocks
264 res = CreateConfigInfoBlk(0x00050005, 0x20, 0xE, STEREO_CAMERA_SETTINGS);
265 if (!res.IsSuccess())
266 return res;
267 res = CreateConfigInfoBlk(0x00090001, 0x8, 0xE, reinterpret_cast<u8 const*>(&CONSOLE_UNIQUE_ID));
268 if (!res.IsSuccess())
269 return res;
270 res = CreateConfigInfoBlk(0x000F0004, 0x4, 0x8, reinterpret_cast<u8 const*>(&CONSOLE_MODEL));
271 if (!res.IsSuccess())
272 return res;
273 // Save the buffer to the file
274 res = UpdateConfigNANDSavegame();
275 if (!res.IsSuccess())
276 return res;
185 return RESULT_SUCCESS; 277 return RESULT_SUCCESS;
186} 278}
187 279
@@ -271,6 +363,8 @@ Interface::Interface() {
271 return; 363 return;
272 } 364 }
273 365
366 // TODO(Subv): All this code should be moved to cfg:i,
367 // it's only here because we do not currently emulate the lower level code that uses that service
274 // Try to open the file in read-only mode to check its existence 368 // Try to open the file in read-only mode to check its existence
275 FileSys::Mode mode; 369 FileSys::Mode mode;
276 mode.hex = 0; 370 mode.hex = 0;
@@ -282,30 +376,7 @@ Interface::Interface() {
282 if (file != nullptr) 376 if (file != nullptr)
283 return; 377 return;
284 378
285 mode.create_flag = 1; 379 FormatConfig();
286 mode.write_flag = 1;
287 mode.read_flag = 0;
288 // Re-open the file in write-create mode
289 file = cfg_system_save_data->OpenFile(path, mode);
290
291 // Setup the default config file data header
292 SaveFileConfig config = { 3, 0, {} };
293 u32 offset = sizeof(SaveFileConfig);
294 // Console-unique ID
295 config.block_entries[0] = { 0x00090001, offset, 0x8, 0xE };
296 offset += 0x8;
297 // Stereo Camera Settings?
298 config.block_entries[1] = { 0x00050005, offset, 0x20, 0xE };
299 offset += 0x20;
300 // System Model (Nintendo 3DS XL)
301 config.block_entries[2] = { 0x000F0004, NINTENDO_3DS_XL, 0x4, 0x8 };
302
303 // Write the config file data header to the config file
304 file->Write(0, sizeof(SaveFileConfig), 1, reinterpret_cast<u8*>(&config));
305 // Write the data itself
306 file->Write(config.block_entries[0].offset_or_data, 0x8, 1,
307 reinterpret_cast<u8 const*>(&CONSOLE_UNIQUE_ID));
308 file->Write(config.block_entries[1].offset_or_data, 0x20, 1, STEREO_CAMERA_SETTINGS);
309} 380}
310 381
311Interface::~Interface() { 382Interface::~Interface() {