Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/bootloader/storage/emummc.c
1471 views
1
/*
2
* Copyright (c) 2019-2022 CTCaer
3
*
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms and conditions of the GNU General Public License,
6
* version 2, as published by the Free Software Foundation.
7
*
8
* This program is distributed in the hope it will be useful, but WITHOUT
9
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11
* more details.
12
*
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15
*/
16
17
#include <string.h>
18
#include <stdlib.h>
19
20
#include <bdk.h>
21
22
#include "emummc.h"
23
#include "../config.h"
24
#include <libs/fatfs/ff.h>
25
26
extern hekate_config h_cfg;
27
emummc_cfg_t emu_cfg = { 0 };
28
29
void emummc_load_cfg()
30
{
31
emu_cfg.enabled = 0;
32
emu_cfg.path = NULL;
33
emu_cfg.sector = 0;
34
emu_cfg.id = 0;
35
emu_cfg.file_based_part_size = 0;
36
emu_cfg.active_part = 0;
37
emu_cfg.fs_ver = 0;
38
if (!emu_cfg.nintendo_path)
39
emu_cfg.nintendo_path = (char *)malloc(0x200);
40
if (!emu_cfg.emummc_file_based_path)
41
emu_cfg.emummc_file_based_path = (char *)malloc(0x200);
42
43
emu_cfg.nintendo_path[0] = 0;
44
emu_cfg.emummc_file_based_path[0] = 0;
45
46
LIST_INIT(ini_sections);
47
if (ini_parse(&ini_sections, "emuMMC/emummc.ini", false))
48
{
49
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
50
{
51
if (ini_sec->type == INI_CHOICE)
52
{
53
if (strcmp(ini_sec->name, "emummc"))
54
continue;
55
56
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
57
{
58
if (!strcmp("enabled", kv->key))
59
emu_cfg.enabled = atoi(kv->val);
60
else if (!strcmp("sector", kv->key))
61
emu_cfg.sector = strtol(kv->val, NULL, 16);
62
else if (!strcmp("id", kv->key))
63
emu_cfg.id = strtol(kv->val, NULL, 16);
64
else if (!strcmp("path", kv->key))
65
emu_cfg.path = kv->val;
66
else if (!strcmp("nintendo_path", kv->key))
67
strcpy(emu_cfg.nintendo_path, kv->val);
68
}
69
break;
70
}
71
}
72
}
73
}
74
75
bool emummc_set_path(char *path)
76
{
77
FIL fp;
78
bool found = false;
79
80
strcpy(emu_cfg.emummc_file_based_path, path);
81
strcat(emu_cfg.emummc_file_based_path, "/raw_based");
82
83
if (!f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
84
{
85
if (!f_read(&fp, &emu_cfg.sector, 4, NULL))
86
if (emu_cfg.sector)
87
found = true;
88
}
89
else
90
{
91
strcpy(emu_cfg.emummc_file_based_path, path);
92
strcat(emu_cfg.emummc_file_based_path, "/file_based");
93
94
if (!f_stat(emu_cfg.emummc_file_based_path, NULL))
95
{
96
emu_cfg.sector = 0;
97
emu_cfg.path = path;
98
99
found = true;
100
}
101
}
102
103
if (found)
104
{
105
emu_cfg.enabled = 1;
106
107
// Get ID from path.
108
u32 id_from_path = 0;
109
u32 path_size = strlen(path);
110
if (path_size >= 4)
111
memcpy(&id_from_path, path + path_size - 4, 4);
112
emu_cfg.id = id_from_path;
113
114
strcpy(emu_cfg.nintendo_path, path);
115
strcat(emu_cfg.nintendo_path, "/Nintendo");
116
}
117
118
return found;
119
}
120
121
static int emummc_raw_get_part_off(int part_idx)
122
{
123
switch (part_idx)
124
{
125
case 0:
126
return 2;
127
case 1:
128
return 0;
129
case 2:
130
return 1;
131
}
132
return 2;
133
}
134
135
int emummc_storage_init_mmc()
136
{
137
FILINFO fno;
138
emu_cfg.active_part = 0;
139
140
// Always init eMMC even when in emuMMC. eMMC is needed from the emuMMC driver anyway.
141
if (!emmc_initialize(false))
142
return 2;
143
144
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
145
return 0;
146
147
if (!sd_mount())
148
goto out;
149
150
if (!emu_cfg.sector)
151
{
152
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
153
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
154
155
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
156
{
157
EPRINTF("Failed to open eMMC folder.");
158
goto out;
159
}
160
f_chmod(emu_cfg.emummc_file_based_path, AM_ARC, AM_ARC);
161
162
strcat(emu_cfg.emummc_file_based_path, "/00");
163
if (f_stat(emu_cfg.emummc_file_based_path, &fno))
164
{
165
EPRINTF("Failed to open emuMMC rawnand.");
166
goto out;
167
}
168
emu_cfg.file_based_part_size = fno.fsize >> 9;
169
}
170
171
return 0;
172
173
out:
174
return 1;
175
}
176
177
int emummc_storage_end()
178
{
179
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
180
emmc_end();
181
else
182
sd_end();
183
184
return 1;
185
}
186
187
int emummc_storage_read(u32 sector, u32 num_sectors, void *buf)
188
{
189
FIL fp;
190
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
191
return sdmmc_storage_read(&emmc_storage, sector, num_sectors, buf);
192
else if (emu_cfg.sector)
193
{
194
sector += emu_cfg.sector;
195
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
196
return sdmmc_storage_read(&sd_storage, sector, num_sectors, buf);
197
}
198
else
199
{
200
if (!emu_cfg.active_part)
201
{
202
u32 file_part = sector / emu_cfg.file_based_part_size;
203
sector = sector % emu_cfg.file_based_part_size;
204
if (file_part >= 10)
205
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
206
else
207
{
208
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
209
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
210
}
211
}
212
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_READ))
213
{
214
EPRINTF("Failed to open emuMMC image.");
215
return 0;
216
}
217
f_lseek(&fp, (u64)sector << 9);
218
if (f_read(&fp, buf, (u64)num_sectors << 9, NULL))
219
{
220
EPRINTF("Failed to read emuMMC image.");
221
f_close(&fp);
222
return 0;
223
}
224
225
f_close(&fp);
226
return 1;
227
}
228
229
return 1;
230
}
231
232
int emummc_storage_write(u32 sector, u32 num_sectors, void *buf)
233
{
234
FIL fp;
235
if (!emu_cfg.enabled || h_cfg.emummc_force_disable)
236
return sdmmc_storage_write(&emmc_storage, sector, num_sectors, buf);
237
else if (emu_cfg.sector)
238
{
239
sector += emu_cfg.sector;
240
sector += emummc_raw_get_part_off(emu_cfg.active_part) * 0x2000;
241
return sdmmc_storage_write(&sd_storage, sector, num_sectors, buf);
242
}
243
else
244
{
245
if (!emu_cfg.active_part)
246
{
247
u32 file_part = sector / emu_cfg.file_based_part_size;
248
sector = sector % emu_cfg.file_based_part_size;
249
if (file_part >= 10)
250
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 2, 10);
251
else
252
{
253
emu_cfg.emummc_file_based_path[strlen(emu_cfg.emummc_file_based_path) - 2] = '0';
254
itoa(file_part, emu_cfg.emummc_file_based_path + strlen(emu_cfg.emummc_file_based_path) - 1, 10);
255
}
256
}
257
258
if (f_open(&fp, emu_cfg.emummc_file_based_path, FA_WRITE))
259
return 0;
260
261
f_lseek(&fp, (u64)sector << 9);
262
if (f_write(&fp, buf, (u64)num_sectors << 9, NULL))
263
{
264
f_close(&fp);
265
return 0;
266
}
267
268
f_close(&fp);
269
return 1;
270
}
271
}
272
273
int emummc_storage_set_mmc_partition(u32 partition)
274
{
275
emu_cfg.active_part = partition;
276
emmc_set_partition(partition);
277
278
if (!emu_cfg.enabled || h_cfg.emummc_force_disable || emu_cfg.sector)
279
return 1;
280
else
281
{
282
strcpy(emu_cfg.emummc_file_based_path, emu_cfg.path);
283
strcat(emu_cfg.emummc_file_based_path, "/eMMC");
284
285
switch (partition)
286
{
287
case 0:
288
strcat(emu_cfg.emummc_file_based_path, "/00");
289
break;
290
case 1:
291
strcat(emu_cfg.emummc_file_based_path, "/BOOT0");
292
break;
293
case 2:
294
strcat(emu_cfg.emummc_file_based_path, "/BOOT1");
295
break;
296
}
297
298
return 1;
299
}
300
301
return 1;
302
}
303
304