summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Subv2014-12-19 15:30:25 -0500
committerGravatar Subv2014-12-21 16:38:59 -0500
commit4cd21b43c1e28933898c4a2e829555efe22ff12e (patch)
treebff4da5013682afa238f56efdc6ffd0ff9e827bf /src
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.
Diffstat (limited to 'src')
-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() {