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