Compare commits
935 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21db0d45bd | ||
|
|
4429cb2095 | ||
|
|
cab54d1b31 | ||
|
|
1d2909ea03 | ||
|
|
d802e5329c | ||
|
|
118f81d347 | ||
|
|
ba3740a77a | ||
|
|
47369c8f5e | ||
|
|
7a05dee453 | ||
|
|
9e47369365 | ||
|
|
5379c05001 | ||
|
|
5b34b2d114 | ||
|
|
3ea8734fdd | ||
|
|
8e22080e05 | ||
|
|
692a94fe5e | ||
|
|
01c760ab88 | ||
|
|
28e5d8107f | ||
|
|
710d8cd15c | ||
|
|
8395540288 | ||
|
|
d57d8aaae7 | ||
|
|
10f555b6fb | ||
|
|
9f30244bfb | ||
|
|
0b65fcbdd7 | ||
|
|
067e217909 | ||
|
|
d6c6c421e9 | ||
|
|
90b54581b0 | ||
|
|
68d9674ca3 | ||
|
|
a9a8edeaf4 | ||
|
|
dd21a3930d | ||
|
|
53209b9be0 | ||
|
|
8308e1a8b8 | ||
|
|
986a2fb5d8 | ||
|
|
9570e6cbec | ||
|
|
93a08c5ef9 | ||
|
|
a187c0c7ce | ||
|
|
43f4475272 | ||
|
|
a7ed32e206 | ||
|
|
6eadac23b3 | ||
|
|
1c7eb8f97a | ||
|
|
a71c5f42fc | ||
|
|
de0f1dc156 | ||
|
|
bb05961f70 | ||
|
|
57900e91ba | ||
|
|
98f650a5de | ||
|
|
55b2db4a8d | ||
|
|
fbe3088744 | ||
|
|
336ab6a64c | ||
|
|
c73fec46e6 | ||
|
|
b493e2bd5f | ||
|
|
78a7d6c5af | ||
|
|
a8b2e9a50c | ||
|
|
2d7c1e42d8 | ||
|
|
64ebec3ea4 | ||
|
|
252d32aafe | ||
|
|
2349370960 | ||
|
|
6ccc0f0538 | ||
|
|
9f12a47cfc | ||
|
|
ee880802c8 | ||
|
|
ab14e77b50 | ||
|
|
1d4245e582 | ||
|
|
8636a74ba4 | ||
|
|
3b766de306 | ||
|
|
1f300e1b75 | ||
|
|
56efe6035f | ||
|
|
73e363d159 | ||
|
|
3ac134bc16 | ||
|
|
c7bb1f9655 | ||
|
|
7847646b3e | ||
|
|
ec6e9f73bb | ||
|
|
bd62f033ab | ||
|
|
ba88ec25f6 | ||
|
|
b9bc41a772 | ||
|
|
e029458b09 | ||
|
|
b3ecf1776b | ||
|
|
5fe83588eb | ||
|
|
18b8eaabae | ||
|
|
e11695c2f0 | ||
|
|
91edbf71c8 | ||
|
|
5b9b22021b | ||
|
|
033d90b866 | ||
|
|
540c0df918 | ||
|
|
6de167467f | ||
|
|
c746326eb3 | ||
|
|
0fbd384a73 | ||
|
|
e8d4a98c7b | ||
|
|
f5aa63936c | ||
|
|
62a57d0f47 | ||
|
|
958fb4c739 | ||
|
|
e231275cbe | ||
|
|
5a404c3a35 | ||
|
|
b1c07c6204 | ||
|
|
60f158d488 | ||
|
|
1887c6fae3 | ||
|
|
725a825762 | ||
|
|
b81f59d5ae | ||
|
|
39c2b8927b | ||
|
|
89dfdac7bf | ||
|
|
c087edf2ba | ||
|
|
db33c315f2 | ||
|
|
c7e7dd8248 | ||
|
|
b10d82a883 | ||
|
|
e151b3d4ef | ||
|
|
5ccf4a45c1 | ||
|
|
c5369a5cad | ||
|
|
b5eba765a5 | ||
|
|
a5ddc38477 | ||
|
|
8d102256a2 | ||
|
|
2e561f7ea9 | ||
|
|
9656fe1b6f | ||
|
|
48c23f2a43 | ||
|
|
6d82649c3c | ||
|
|
81dea35754 | ||
|
|
fdbe43421b | ||
|
|
0d71560785 | ||
|
|
108e8a0cd4 | ||
|
|
653e81c48e | ||
|
|
0dc0783094 | ||
|
|
13ef1bf6be | ||
|
|
7ea80353f6 | ||
|
|
07bbff7d11 | ||
|
|
2ff4fc3cdd | ||
|
|
c9456055ea | ||
|
|
2900f2d67b | ||
|
|
93c8c90804 | ||
|
|
36e54642d2 | ||
|
|
e04cb28711 | ||
|
|
ad1dc51e06 | ||
|
|
5b6bab7a58 | ||
|
|
9bd2fc659d | ||
|
|
f18633f65f | ||
|
|
1026bc7b4f | ||
|
|
f1dee68142 | ||
|
|
f7cc2d295c | ||
|
|
a6f254b5cf | ||
|
|
00dbbe1b28 | ||
|
|
7f33309903 | ||
|
|
c95808fa2d | ||
|
|
5b6bd048a9 | ||
|
|
28e6ad3372 | ||
|
|
9b128ebba5 | ||
|
|
71f49180c3 | ||
|
|
4a042241a8 | ||
|
|
0eab9127e3 | ||
|
|
9f11991410 | ||
|
|
fec0b95098 | ||
|
|
5081439f53 | ||
|
|
c44aebee4d | ||
|
|
706cd50f25 | ||
|
|
b1b81c87f2 | ||
|
|
bf7e30539e | ||
|
|
5f8a61201b | ||
|
|
ed8aee8b8c | ||
|
|
92ec2af587 | ||
|
|
7960c87579 | ||
|
|
700d572732 | ||
|
|
014a0d86f1 | ||
|
|
88db59405f | ||
|
|
ef2e008700 | ||
|
|
07101c053a | ||
|
|
6c5f6ac475 | ||
|
|
61ecd9a617 | ||
|
|
6f56a9bfe9 | ||
|
|
416875ee46 | ||
|
|
c875b506ea | ||
|
|
ff4517e583 | ||
|
|
92cc989dc9 | ||
|
|
6e5987e3ca | ||
|
|
f03e232b90 | ||
|
|
1eb18c1790 | ||
|
|
3076d56973 | ||
|
|
b35707edf9 | ||
|
|
dfbd0dc9e7 | ||
|
|
620ad7ba71 | ||
|
|
5e4fd53243 | ||
|
|
0ba7630354 | ||
|
|
028d0ec0d5 | ||
|
|
751fa05fcd | ||
|
|
f89845257e | ||
|
|
2f274e2f47 | ||
|
|
38088e80e1 | ||
|
|
14162828ea | ||
|
|
ab8507e09d | ||
|
|
0d25c07333 | ||
|
|
bfc8ba8447 | ||
|
|
a45f8293d9 | ||
|
|
f29b9d14d7 | ||
|
|
9c9fd2deef | ||
|
|
3bb01ffd68 | ||
|
|
bc6d9994dc | ||
|
|
e177f9e0fe | ||
|
|
c5d75d2de9 | ||
|
|
cc0cade4d2 | ||
|
|
1e3362250f | ||
|
|
db16e8d602 | ||
|
|
2a563eddd0 | ||
|
|
6b8474b7b9 | ||
|
|
b5336c81cc | ||
|
|
1fcab825bf | ||
|
|
0306556032 | ||
|
|
b093578046 | ||
|
|
9332b9eb33 | ||
|
|
141c7817a0 | ||
|
|
f155026d8f | ||
|
|
37e467ba60 | ||
|
|
3572b835b5 | ||
|
|
da4f3a72af | ||
|
|
2938bbd11f | ||
|
|
abf3017eb2 | ||
|
|
5c855ea52f | ||
|
|
c83edea7ad | ||
|
|
6d3113c8c3 | ||
|
|
48c48c7bbc | ||
|
|
e4093ed988 | ||
|
|
c79af52720 | ||
|
|
61eeaca6d5 | ||
|
|
320a79ba72 | ||
|
|
2e1b943805 | ||
|
|
bc167dde2d | ||
|
|
7d9a8b4211 | ||
|
|
0b16d88756 | ||
|
|
796cb31ed7 | ||
|
|
d7fd2f26c1 | ||
|
|
5adb8749de | ||
|
|
3474faa4a2 | ||
|
|
acd9c04ff6 | ||
|
|
833c9406b0 | ||
|
|
2f1253e27f | ||
|
|
53b847e31c | ||
|
|
7efa33dd7f | ||
|
|
4011970a57 | ||
|
|
a2cfa2be16 | ||
|
|
c4b691d688 | ||
|
|
72a7a8eee5 | ||
|
|
52d352385f | ||
|
|
c1f85650bd | ||
|
|
b830909504 | ||
|
|
4ad6b1c220 | ||
|
|
429488a4ba | ||
|
|
40c6cc11a5 | ||
|
|
594881c6ce | ||
|
|
1cc64a0fbc | ||
|
|
f492318e3c | ||
|
|
4b06bb7795 | ||
|
|
f7e570383a | ||
|
|
896a088199 | ||
|
|
f3322bd003 | ||
|
|
cef947d67d | ||
|
|
b6640d118d | ||
|
|
273d0b2ce9 | ||
|
|
9b724d776e | ||
|
|
3eaa706ccf | ||
|
|
b4c854dfe8 | ||
|
|
9cdadbe834 | ||
|
|
b3f38a8764 | ||
|
|
5d868284c6 | ||
|
|
035751980d | ||
|
|
6b80bc08d5 | ||
|
|
2089959d1b | ||
|
|
67b00ec28d | ||
|
|
127ae6b945 | ||
|
|
4f53b3ce35 | ||
|
|
c3092b482a | ||
|
|
080219f88d | ||
|
|
3fd783cd01 | ||
|
|
211cd964d7 | ||
|
|
04f42f0be4 | ||
|
|
e00ef893d0 | ||
|
|
858efa604e | ||
|
|
b63b17c54f | ||
|
|
f0e111c20e | ||
|
|
7339f57138 | ||
|
|
1e39c999f9 | ||
|
|
62f7a06192 | ||
|
|
a0531b7930 | ||
|
|
0619d04939 | ||
|
|
cd76476d26 | ||
|
|
53b6c17e33 | ||
|
|
3b7b66b272 | ||
|
|
a795a45c34 | ||
|
|
b58cbd228c | ||
|
|
fc994285f9 | ||
|
|
d5e74b91c7 | ||
|
|
c5eb2e1070 | ||
|
|
d613cb057e | ||
|
|
121792bebe | ||
|
|
e07c230106 | ||
|
|
d5ce3044c8 | ||
|
|
98ff43b4d2 | ||
|
|
1704fbcd62 | ||
|
|
014ac1cf72 | ||
|
|
b499c7ee75 | ||
|
|
2e069e326c | ||
|
|
e47d42da22 | ||
|
|
615e5dfaa7 | ||
|
|
fde2c371ef | ||
|
|
a0b4e7fd5d | ||
|
|
45c36bbcae | ||
|
|
66c041ad93 | ||
|
|
32d5c52b5f | ||
|
|
9cf5b01633 | ||
|
|
d4cf22d370 | ||
|
|
973640f023 | ||
|
|
248ea82f76 | ||
|
|
a868079a93 | ||
|
|
d270d5b9ca | ||
|
|
e9692a438b | ||
|
|
06ea123dbd | ||
|
|
85141d5eda | ||
|
|
fa13b8fbd0 | ||
|
|
5b4712644a | ||
|
|
aa422914bd | ||
|
|
22c453e297 | ||
|
|
e5f40cec5a | ||
|
|
50b24bf6c2 | ||
|
|
b575ee9e28 | ||
|
|
37030621ac | ||
|
|
f005da4d12 | ||
|
|
6295559d9c | ||
|
|
f36ff303d9 | ||
|
|
1a62e91c01 | ||
|
|
7f314dfe11 | ||
|
|
0caf9f4214 | ||
|
|
1ad600c81a | ||
|
|
bd6c7b7fdb | ||
|
|
5f93724845 | ||
|
|
ad60eac6ef | ||
|
|
b3e3a2937a | ||
|
|
d010038228 | ||
|
|
c28eada93e | ||
|
|
9d84a92b1f | ||
|
|
7884be106d | ||
|
|
5fe7c7e7e1 | ||
|
|
f244b95aad | ||
|
|
3b5a5759b8 | ||
|
|
528e7ee33b | ||
|
|
c1f55735fc | ||
|
|
185ea86284 | ||
|
|
618262f015 | ||
|
|
c0f41ac10e | ||
|
|
3010699f20 | ||
|
|
fb274538e1 | ||
|
|
1a5d953a98 | ||
|
|
2dd1baebb3 | ||
|
|
d46beac22a | ||
|
|
6ed8741006 | ||
|
|
6845e42f2c | ||
|
|
5196869634 | ||
|
|
083806bfc9 | ||
|
|
11d29368ce | ||
|
|
100c3d9e36 | ||
|
|
01fbf8c3a5 | ||
|
|
a36556d7e4 | ||
|
|
4f11162fae | ||
|
|
2cbaf39fd5 | ||
|
|
2cc46c618b | ||
|
|
a0325e91f9 | ||
|
|
e11edd5dee | ||
|
|
5e8990f571 | ||
|
|
a3fd55036a | ||
|
|
7a3d15c48b | ||
|
|
a5b52a2470 | ||
|
|
a8cd14dafd | ||
|
|
2b249bd496 | ||
|
|
c8586cfe26 | ||
|
|
f228cb241f | ||
|
|
fd33ef8496 | ||
|
|
ba1cf6473a | ||
|
|
f418dcdb7b | ||
|
|
f91c26d752 | ||
|
|
f7156f2ff2 | ||
|
|
e444b587cf | ||
|
|
a7fcc6a5cf | ||
|
|
872b1ccbb6 | ||
|
|
b7b3400296 | ||
|
|
420ccdcb82 | ||
|
|
eaa4d6323e | ||
|
|
4e7ac41a6c | ||
|
|
92f3a736a7 | ||
|
|
5a30b2b298 | ||
|
|
85aaae67bf | ||
|
|
efe66bc72e | ||
|
|
d7bdf3fc19 | ||
|
|
c4e5f4410c | ||
|
|
f5039dca56 | ||
|
|
de6f9789cb | ||
|
|
4376a1093f | ||
|
|
a413ed01f3 | ||
|
|
05bb831321 | ||
|
|
6e0f1e5235 | ||
|
|
2f915401dd | ||
|
|
14152b3072 | ||
|
|
8f3cba37b3 | ||
|
|
0853f6f7ad | ||
|
|
ae7a7ba365 | ||
|
|
724af0fdc4 | ||
|
|
550ea2116e | ||
|
|
7952271d61 | ||
|
|
ffaa5790c2 | ||
|
|
934c4bed0b | ||
|
|
6f040caa98 | ||
|
|
50e5c29b1c | ||
|
|
e0b5539b91 | ||
|
|
050f58a3bb | ||
|
|
c739ed8e48 | ||
|
|
a09fc6ebcb | ||
|
|
4367ea6afa | ||
|
|
da0adeb39e | ||
|
|
63160a22a6 | ||
|
|
2bc1927ebd | ||
|
|
66e0cfc185 | ||
|
|
7bd0e4f5b4 | ||
|
|
7271850df2 | ||
|
|
8c79285774 | ||
|
|
56a77ceac1 | ||
|
|
3034420ac2 | ||
|
|
99a157649d | ||
|
|
e6645554f0 | ||
|
|
0f83d1ffaa | ||
|
|
2286eb21a7 | ||
|
|
64c81aa5f8 | ||
|
|
29dcfca608 | ||
|
|
f1cb9630ec | ||
|
|
ebbea57400 | ||
|
|
6016dc14f8 | ||
|
|
dc8e4e5f14 | ||
|
|
72c8212a0e | ||
|
|
2cd2a081d6 | ||
|
|
b44ec544f4 | ||
|
|
063eae7e95 | ||
|
|
2552572904 | ||
|
|
b74dda42a2 | ||
|
|
6e178e2069 | ||
|
|
277d723992 | ||
|
|
2f6afe9932 | ||
|
|
edcc617780 | ||
|
|
5d39242b83 | ||
|
|
ddbe5fd27b | ||
|
|
deb91d1d02 | ||
|
|
63073ea07f | ||
|
|
a331fcd873 | ||
|
|
99654bd5b2 | ||
|
|
f10427287f | ||
|
|
5b6318ee3a | ||
|
|
98cdbe0784 | ||
|
|
e4eb3ae38d | ||
|
|
6686e4add7 | ||
|
|
96a274bf7d | ||
|
|
add17a7994 | ||
|
|
26e404c6a2 | ||
|
|
144de8b328 | ||
|
|
c0226e6fd9 | ||
|
|
57d728a9be | ||
|
|
b2e9f5377b | ||
|
|
d3d315784c | ||
|
|
942a371b6a | ||
|
|
66ffc78f60 | ||
|
|
a9570cef14 | ||
|
|
16bc08f046 | ||
|
|
024335e5cd | ||
|
|
8f32048774 | ||
|
|
33d3dd256d | ||
|
|
fc151f7595 | ||
|
|
9152884815 | ||
|
|
2b4e97bec5 | ||
|
|
a63393504f | ||
|
|
97ae8d2d44 | ||
|
|
6c59728516 | ||
|
|
201fe05a06 | ||
|
|
a78889523f | ||
|
|
5cd1a207c9 | ||
|
|
423f0ca631 | ||
|
|
7612e38d41 | ||
|
|
bf234950cb | ||
|
|
bd992fca15 | ||
|
|
45fee57abd | ||
|
|
a2bca96d47 | ||
|
|
9862256ca7 | ||
|
|
6afc8b3b5c | ||
|
|
9b4b4ec543 | ||
|
|
d412711868 | ||
|
|
0b33551d94 | ||
|
|
9c1b585054 | ||
|
|
fc3a69d9ca | ||
|
|
cce4a6d07f | ||
|
|
b16539408b | ||
|
|
eba56d0f64 | ||
|
|
f2181b1d3e | ||
|
|
c93a97f8d7 | ||
|
|
8fd2525cd1 | ||
|
|
62a70cfdac | ||
|
|
ca0a79fc89 | ||
|
|
104b8e859f | ||
|
|
a99b26ff8c | ||
|
|
9bc62ec12d | ||
|
|
84a6bb772f | ||
|
|
263a5eda56 | ||
|
|
7fb17ce52f | ||
|
|
631fad24c0 | ||
|
|
f1d77fa62a | ||
|
|
3bc247b43b | ||
|
|
3608799dff | ||
|
|
c0f042bc2a | ||
|
|
8982ff259a | ||
|
|
726b06b748 | ||
|
|
0057ab9c5a | ||
|
|
048bf0ee4d | ||
|
|
4da0708b51 | ||
|
|
4c529e3145 | ||
|
|
8ceeca372f | ||
|
|
4326ac9be1 | ||
|
|
697c64abe4 | ||
|
|
7e8cf84c42 | ||
|
|
b6d91375a5 | ||
|
|
61305688fd | ||
|
|
492ae4139f | ||
|
|
a84f393bd5 | ||
|
|
5de54d6f9f | ||
|
|
8fc797120f | ||
|
|
5406d648bc | ||
|
|
a2003fba95 | ||
|
|
a76c15d018 | ||
|
|
ae8caf3d3a | ||
|
|
f221915a95 | ||
|
|
7f93733107 | ||
|
|
e8b9e49f57 | ||
|
|
cb9576b10e | ||
|
|
06fe06f9f1 | ||
|
|
abf7c8e565 | ||
|
|
46227e6763 | ||
|
|
2ffe4a5451 | ||
|
|
18bd4bbcf6 | ||
|
|
8209433696 | ||
|
|
ad9e00acaa | ||
|
|
c96f96258f | ||
|
|
82699f3e00 | ||
|
|
e2d828a4a2 | ||
|
|
92328c6a7e | ||
|
|
3f8ad17e86 | ||
|
|
52999db43a | ||
|
|
760aa99709 | ||
|
|
51c514de84 | ||
|
|
317899b4bf | ||
|
|
4c93d2b1f9 | ||
|
|
71c5404bfe | ||
|
|
9c5248b87a | ||
|
|
83a0293af4 | ||
|
|
84f3eddaf8 | ||
|
|
a5c6b908b6 | ||
|
|
94f0d873df | ||
|
|
d6f66d24fa | ||
|
|
31458e9938 | ||
|
|
dca612ffd7 | ||
|
|
5177308d48 | ||
|
|
59ab44a8c7 | ||
|
|
c711ed6253 | ||
|
|
58c6be17eb | ||
|
|
259bcc686c | ||
|
|
356268eae5 | ||
|
|
2dd64b8a92 | ||
|
|
b5cddedb7d | ||
|
|
7afdc2b3b5 | ||
|
|
60c4956290 | ||
|
|
4c6a2f7ab1 | ||
|
|
76cee0d95b | ||
|
|
7331a919e4 | ||
|
|
27ea6b96c4 | ||
|
|
33238cee54 | ||
|
|
384dd2ad81 | ||
|
|
4885e0b8d8 | ||
|
|
2a84911d3b | ||
|
|
7f672fb417 | ||
|
|
a13fdeecf6 | ||
|
|
74ac76ba84 | ||
|
|
253e031f83 | ||
|
|
ef1ecf859c | ||
|
|
a302ad3bea | ||
|
|
0951260df7 | ||
|
|
b87dadbb72 | ||
|
|
1dd6a9821a | ||
|
|
50a2424001 | ||
|
|
61e5a4444f | ||
|
|
de3eb6ccd7 | ||
|
|
4f8c66b2b7 | ||
|
|
4d9cbc4e19 | ||
|
|
40369d44df | ||
|
|
ee3720f0b7 | ||
|
|
e5dcca1c2b | ||
|
|
ef8438a214 | ||
|
|
dfd699c16b | ||
|
|
a381c2a811 | ||
|
|
e4c87a59d0 | ||
|
|
eef30ceb3c | ||
|
|
76411387ba | ||
|
|
8d5d8d2100 | ||
|
|
802bce12a7 | ||
|
|
a1024c288e | ||
|
|
a4531b01d5 | ||
|
|
d445b20e90 | ||
|
|
24ddf5ca3d | ||
|
|
bb117d3d74 | ||
|
|
c101653077 | ||
|
|
5248b96f8a | ||
|
|
7ab59e420a | ||
|
|
83a849126a | ||
|
|
c9c373f607 | ||
|
|
aa7c2c0009 | ||
|
|
57fc4df86f | ||
|
|
75acdc8a98 | ||
|
|
070f7fcc68 | ||
|
|
4d48238fb1 | ||
|
|
9b304404f7 | ||
|
|
8e5ced8e3c | ||
|
|
95ef379ac5 | ||
|
|
915f9ccb0d | ||
|
|
3709ac301a | ||
|
|
3bc966f84e | ||
|
|
457b4cec13 | ||
|
|
88891ef6cd | ||
|
|
25811e2b52 | ||
|
|
f81c92e35b | ||
|
|
39b2aff627 | ||
|
|
905777466d | ||
|
|
4e21cf4f1c | ||
|
|
eccf9eab93 | ||
|
|
c36ad54bcb | ||
|
|
81e2b7c11c | ||
|
|
18b5cdcddf | ||
|
|
fe31114779 | ||
|
|
df30a2a320 | ||
|
|
cf7fa8ecbd | ||
|
|
389a169443 | ||
|
|
e01802e299 | ||
|
|
709aefba5d | ||
|
|
e4ed713fce | ||
|
|
d3c507b0d4 | ||
|
|
a68e14def3 | ||
|
|
8175642a2a | ||
|
|
8d1befea9e | ||
|
|
e7b8a0ef39 | ||
|
|
be6ee894f9 | ||
|
|
e0e8ed2113 | ||
|
|
c63e46b1a9 | ||
|
|
eb9c74a1ed | ||
|
|
efd83e063e | ||
|
|
ae23a1c84d | ||
|
|
fd1253caac | ||
|
|
a0e8bc1de3 | ||
|
|
004f0652c9 | ||
|
|
d5190cd788 | ||
|
|
2412faf033 | ||
|
|
72caad86cc | ||
|
|
7df9917a00 | ||
|
|
575adcbb9d | ||
|
|
2d6debddb9 | ||
|
|
53d2aac2ae | ||
|
|
96211813e3 | ||
|
|
153bbd6242 | ||
|
|
730e716f0f | ||
|
|
2238293c0f | ||
|
|
29d8e637d8 | ||
|
|
136e0d8974 | ||
|
|
0eb87df84f | ||
|
|
a9db998d84 | ||
|
|
fcb8edffdf | ||
|
|
61684ecb68 | ||
|
|
0ced86b55f | ||
|
|
159c9cb475 | ||
|
|
2943dcb2e9 | ||
|
|
984c3e549c | ||
|
|
edfd63e1f7 | ||
|
|
e593584a47 | ||
|
|
ef60c8ea4c | ||
|
|
e478908dca | ||
|
|
ca587692eb | ||
|
|
f78dd5365c | ||
|
|
f9d6cdccb0 | ||
|
|
35fdd470b3 | ||
|
|
edff11be7b | ||
|
|
bb230de72c | ||
|
|
2d7dde9cf9 | ||
|
|
b77d619873 | ||
|
|
ae1033d975 | ||
|
|
99d28c4f79 | ||
|
|
2424865fa1 | ||
|
|
6a280723f8 | ||
|
|
f85bbfff58 | ||
|
|
d239d82379 | ||
|
|
9017de6082 | ||
|
|
477414a636 | ||
|
|
5fac49447c | ||
|
|
30b3a51309 | ||
|
|
bafba1197e | ||
|
|
2fab0be5e8 | ||
|
|
7ea2a0a278 | ||
|
|
a3ae38520c | ||
|
|
c36fa01651 | ||
|
|
9aeac7af92 | ||
|
|
859944dc8e | ||
|
|
a6dc3c8fc7 | ||
|
|
61c02ed079 | ||
|
|
afc6f51ff2 | ||
|
|
c32eefaa51 | ||
|
|
b6969cf0d1 | ||
|
|
58a33ee6e9 | ||
|
|
050f433046 | ||
|
|
d48f6b62ce | ||
|
|
ffee64c67f | ||
|
|
8cbc535755 | ||
|
|
ca07af2fe9 | ||
|
|
2fe5da97eb | ||
|
|
6ffaeadd1b | ||
|
|
2c10b6bff2 | ||
|
|
76acfd9934 | ||
|
|
06cc4f7172 | ||
|
|
158659e5b0 | ||
|
|
7e46046e3b | ||
|
|
808c4b7361 | ||
|
|
03dc4fc425 | ||
|
|
b4029dcd73 | ||
|
|
1750b256eb | ||
|
|
d00d82ac89 | ||
|
|
edb5a82a89 | ||
|
|
f7552f7c32 | ||
|
|
4483b65b25 | ||
|
|
d2f53626ae | ||
|
|
ac01fe417e | ||
|
|
2fd8c7aace | ||
|
|
b90b138766 | ||
|
|
c3ad7eda08 | ||
|
|
02c6a3c214 | ||
|
|
8dd9c1a1af | ||
|
|
be54052b6d | ||
|
|
9e87679ee2 | ||
|
|
17964f8cd1 | ||
|
|
a63fb971d4 | ||
|
|
4b500349e6 | ||
|
|
8e554e17c9 | ||
|
|
1d77206ae4 | ||
|
|
4340c326dc | ||
|
|
c6cb97ae30 | ||
|
|
9d68c980e6 | ||
|
|
e2596a0a61 | ||
|
|
17d3c6491a | ||
|
|
f55fc421ea | ||
|
|
169b12fc20 | ||
|
|
905f816bbe | ||
|
|
fef48a449a | ||
|
|
95d06c115a | ||
|
|
113059e57c | ||
|
|
408c70b90c | ||
|
|
5b51574ebf | ||
|
|
1e6d7a5aee | ||
|
|
a28b50cee8 | ||
|
|
df112b550b | ||
|
|
85615d1916 | ||
|
|
c6d3158b56 | ||
|
|
4a4de608ec | ||
|
|
e651c3d9cc | ||
|
|
9c12496b30 | ||
|
|
bfc2448662 | ||
|
|
faa04b0309 | ||
|
|
ca1ea7fd6e | ||
|
|
57dc1b09ad | ||
|
|
5a9d0e2569 | ||
|
|
f6d3abbc11 | ||
|
|
041ca8451e | ||
|
|
9ab3a7c451 | ||
|
|
2382e6d82c | ||
|
|
f0e1937eeb | ||
|
|
efd08ff731 | ||
|
|
f9a1f1a79b | ||
|
|
a736e4602a | ||
|
|
5202ba8826 | ||
|
|
0f1bc98bb7 | ||
|
|
d40722af53 | ||
|
|
c9781ab626 | ||
|
|
4cbf4e93e7 | ||
|
|
1f68c2da42 | ||
|
|
d786c292f3 | ||
|
|
ada3e09784 | ||
|
|
c928b3b68b | ||
|
|
ae9c29629c | ||
|
|
3fd4603553 | ||
|
|
c14526068a | ||
|
|
180b2a6f4d | ||
|
|
b926ab7dd2 | ||
|
|
19d8861d27 | ||
|
|
70e82e627b | ||
|
|
67e229e5a9 | ||
|
|
d0d6baaa85 | ||
|
|
fd4352a1d6 | ||
|
|
08808da741 | ||
|
|
a11124a3d6 | ||
|
|
d2d6e786c7 | ||
|
|
a76c943c01 | ||
|
|
3c64a3a234 | ||
|
|
06060c67b5 | ||
|
|
0f64fd73ec | ||
|
|
2323528975 | ||
|
|
22b38a0f88 | ||
|
|
034c0f8d7c | ||
|
|
b4cd67cb8c | ||
|
|
be83d77187 | ||
|
|
615cf81a9f | ||
|
|
c60ef7fe82 | ||
|
|
fea5a111a9 | ||
|
|
7eebfd4f6a | ||
|
|
939965b5a0 | ||
|
|
a0334120a6 | ||
|
|
308417a48e | ||
|
|
85533411c9 | ||
|
|
6d4a84a325 | ||
|
|
89350b1edd | ||
|
|
9e58e4ed7a | ||
|
|
f8f4ecea27 | ||
|
|
e9449f86bf | ||
|
|
4fabe1f704 | ||
|
|
ef3ba896d5 | ||
|
|
649b160292 | ||
|
|
697bc74535 | ||
|
|
0e9ff44746 | ||
|
|
49d49e637a | ||
|
|
b3f0d13aa4 | ||
|
|
bd1547710e | ||
|
|
7479bf8092 | ||
|
|
d4d281bb9c | ||
|
|
68bf134017 | ||
|
|
c7b90f739f | ||
|
|
160bc36ae8 | ||
|
|
464bf1680c | ||
|
|
c51eaba18c | ||
|
|
7dbded99a2 | ||
|
|
6351e5b8c3 | ||
|
|
5a0f2e4dfc | ||
|
|
6d06ea6975 | ||
|
|
4180261f1f | ||
|
|
e882dd7aaf | ||
|
|
9e851d2dfd | ||
|
|
21a3edb150 | ||
|
|
3aacbd17ce | ||
|
|
6f8a9421ef | ||
|
|
bb437f6f7b | ||
|
|
0001f301f8 | ||
|
|
f7bbc4bfec | ||
|
|
a127a38438 | ||
|
|
16225b97d7 | ||
|
|
0587c14162 | ||
|
|
a181bba9f2 | ||
|
|
993e564fbb | ||
|
|
956829864c | ||
|
|
24186a7148 | ||
|
|
3475cfe1e6 | ||
|
|
6b64a10362 | ||
|
|
5e99fb3aa0 | ||
|
|
060d8e9945 | ||
|
|
1026471842 | ||
|
|
645208ec82 | ||
|
|
f4c48a64ca | ||
|
|
c80ac985fe | ||
|
|
ac9bdc7665 | ||
|
|
217d75024d | ||
|
|
12e5b4adb9 | ||
|
|
945f80993b | ||
|
|
5f32779ceb | ||
|
|
e8ebb2f7fe | ||
|
|
034e63669a | ||
|
|
c75ed567fc | ||
|
|
1e2bf61dcf | ||
|
|
de4fea77a1 | ||
|
|
441c143b3e | ||
|
|
feff28a4fe | ||
|
|
b3d25ce64a | ||
|
|
0f44205959 | ||
|
|
1861d556a6 | ||
|
|
9b1df43687 | ||
|
|
56e0157d64 | ||
|
|
d23cd5acd5 | ||
|
|
39a9eb5ccb | ||
|
|
c413b6d07f | ||
|
|
85a59264c9 | ||
|
|
7f96e47b4f | ||
|
|
02b5c69802 | ||
|
|
b5eb108393 | ||
|
|
0a9cd09cc3 | ||
|
|
af451b4997 | ||
|
|
a5f8ccc3ea | ||
|
|
28cdcfed9c | ||
|
|
ea3e45d40a | ||
|
|
8daf3ebe3f | ||
|
|
7ad55ed61e | ||
|
|
96e46b2234 | ||
|
|
094b88b6aa | ||
|
|
03a6e343db | ||
|
|
b42f9ffb41 | ||
|
|
39280e397a | ||
|
|
887707ea87 | ||
|
|
279f39bc13 | ||
|
|
b7b734bad1 | ||
|
|
d01d9b53f2 | ||
|
|
c542bc5cf3 | ||
|
|
1f5b824c27 | ||
|
|
cb84a6c7ea | ||
|
|
61564e5fcf | ||
|
|
a437e533f5 | ||
|
|
6b88953517 | ||
|
|
9b9f784c26 | ||
|
|
6dfb33191f | ||
|
|
078fce4b3d | ||
|
|
dcb09a9472 | ||
|
|
8ce395caa5 | ||
|
|
e9410c86b1 | ||
|
|
42885560ed | ||
|
|
796e4dd060 | ||
|
|
9468582d83 | ||
|
|
6707a36ffe | ||
|
|
09cc7c903c | ||
|
|
9be7481c14 | ||
|
|
9f68ce0d70 | ||
|
|
4748c0292c | ||
|
|
c3ebce1666 | ||
|
|
b1a428f6bc | ||
|
|
3e0b928db0 | ||
|
|
09380a19ff | ||
|
|
04978ebb01 | ||
|
|
478ebeadf8 | ||
|
|
13fd33a61d | ||
|
|
4bdba9f8e9 | ||
|
|
99829b3cf7 | ||
|
|
d4a3ce2d0d | ||
|
|
a58cb05f2c | ||
|
|
9ab6d107b4 | ||
|
|
42cbead456 | ||
|
|
90ebe78c8e | ||
|
|
bf81ec252e | ||
|
|
899ad1887a |
89
.github/ISSUE_TEMPLATE.md
vendored
Normal file
89
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
<!--
|
||||
-- THIS IS NOT A SUPPORT FORUM! For support go here:
|
||||
-- Luma3DS GBATemp thread: https://gbatemp.net/threads/luma3ds-noob-proof-3ds-custom-firmware.411110/
|
||||
-- Nintendo Hacking: https://discord.gg/MjzatM8y
|
||||
--
|
||||
-- Also check the Wiki (https://github.com/AuroraWright/Luma3DS/wiki) before making an issue.
|
||||
--
|
||||
-- For GBA/DSiWare/DS/AGB_FIRM/TWL_FIRM problems: https://3ds.guide/troubleshooting
|
||||
-- If you're using an emu/redNAND anything related to that must also be installed to sysNAND.
|
||||
-- Please make sure to read "Enable game patching" https://github.com/AuroraWright/Luma3DS/wiki/Options-and-usage before posting any issues about the "Enable game patching" option(s).
|
||||
--
|
||||
-- Luma updaters that don't support Boot9Strap/Sighax won't work.
|
||||
-- This is due to support for non-B9S/Sighax entrypoints being dropped.
|
||||
--
|
||||
-- Please fill in the placeholders.-->
|
||||
**System model:**
|
||||
|
||||
[e.g. 2DS, New 3DS, Old 3DS]
|
||||
|
||||
**SysNAND version (+emu/redNAND version if applicable):**
|
||||
|
||||
[e.g. 11.4.0-37U SysNAND, 11.4.0-37J EmuNAND]
|
||||
|
||||
**Entrypoint (How/what you're using to boot Luma3DS):**
|
||||
|
||||
[e.g. Boot9Strap/Sighax, etc.]
|
||||
|
||||
**Luma3DS version:**
|
||||
|
||||
[e.g. 7.1 stable or if using nightly/hourly specify the commit like this https://github.com/AuroraWright/Luma3DS/commit/9570e6cbeca53128433abbf5e3473cb8a07fe69e]
|
||||
<!--You can check which version you're on in System Settings. It will be on the bottom right of the top screen.-->
|
||||
|
||||
|
||||
**Luma3DS configuration/options:**
|
||||
|
||||
Default EmuNAND: ( )
|
||||
|
||||
Screen brightness: ( )
|
||||
|
||||
Splash: ( )
|
||||
|
||||
PIN lock: ( )
|
||||
|
||||
New 3DS CPU: ( )
|
||||
<!--This option is only available for New 3DS/2DS.-->
|
||||
|
||||
--
|
||||
|
||||
Autoboot EmuNAND: ( )
|
||||
|
||||
Use EmuNAND FIRM if booting with R: ( )
|
||||
|
||||
Enable loading external FIRMs and modules: ( )
|
||||
<!--Firmware (.bin) files are not required by Luma, or NTR CFW anymore.
|
||||
-- If you're having issues with this option enabled try deleting them from the luma folder on the root of the SD card and disabling this option.-->
|
||||
|
||||
Use custom path: ( )
|
||||
|
||||
Enable game patching: ( )
|
||||
|
||||
Show NAND or user string in System Settings: ( )
|
||||
|
||||
Show GBA boot screen in patched AGB_FIRM: ( )
|
||||
|
||||
Patch ARM9 access: ( )
|
||||
|
||||
Set developer UNITINFO: ( )
|
||||
|
||||
--
|
||||
|
||||
|
||||
**Explanation of the issue:**
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
**Steps to reproduce:**
|
||||
|
||||
1.
|
||||
|
||||
2.
|
||||
|
||||
|
||||
**Dump file:**
|
||||
<!--If the issue leads to a crash you can generate a crash dump by checking the "Enable exception handlers" option.
|
||||
-- The error message will tell you where the dump is.
|
||||
-- Zip the dmp file and drag & drop it below.-->
|
||||
18
.gitignore
vendored
18
.gitignore
vendored
@@ -1,12 +1,18 @@
|
||||
out
|
||||
CakeHax
|
||||
CakeBrah
|
||||
build
|
||||
data
|
||||
arm11/build
|
||||
sysmodules/loader/build
|
||||
chainloader/build
|
||||
rosalina/build
|
||||
exceptions/arm9/build
|
||||
exceptions/arm11/build
|
||||
.vscode
|
||||
.vscode/**
|
||||
*.bin
|
||||
*.3dsx
|
||||
*.smdh
|
||||
*.firm
|
||||
*.o
|
||||
*.d
|
||||
*.elf
|
||||
*.bat
|
||||
*.cxi
|
||||
*.bmp
|
||||
*.dmp
|
||||
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,6 +0,0 @@
|
||||
[submodule "CakeBrah"]
|
||||
path = CakeBrah
|
||||
url = https://github.com/mid-kid/CakeBrah
|
||||
[submodule "CakeHax"]
|
||||
path = CakeHax
|
||||
url = https://github.com/mid-kid/CakeHax
|
||||
1
CakeBrah
1
CakeBrah
Submodule CakeBrah deleted from aca4aa7d3b
1
CakeHax
1
CakeHax
Submodule CakeHax deleted from 6b8fca0b37
181
Makefile
181
Makefile
@@ -1,107 +1,140 @@
|
||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||
|
||||
CC := arm-none-eabi-gcc
|
||||
AS := arm-none-eabi-as
|
||||
LD := arm-none-eabi-ld
|
||||
OC := arm-none-eabi-objcopy
|
||||
OPENSSL := openssl
|
||||
|
||||
PYTHON3 := python
|
||||
PYTHON_VER_MAJOR := $(word 2, $(subst ., , $(shell python --version 2>&1)))
|
||||
ifneq ($(PYTHON_VER_MAJOR), 3)
|
||||
PYTHON3 := py -3
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
name := ReiNand
|
||||
ifneq ($(strip $(shell firmtool -v 2>&1 | grep usage)),)
|
||||
$(error "Please install firmtool v1.1 or greater")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := Luma3DS
|
||||
revision := $(shell git describe --tags --match v[0-9]* --abbrev=8 | sed 's/-[0-9]*-g/-/i')
|
||||
commit := $(shell git rev-parse --short=8 HEAD)
|
||||
|
||||
ifeq ($(strip $(revision)),)
|
||||
revision := v0.0.0-0
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(commit)),)
|
||||
commit := 0
|
||||
endif
|
||||
|
||||
dir_source := source
|
||||
dir_data := data
|
||||
dir_patches := patches
|
||||
dir_arm11 := arm11
|
||||
dir_chainloader := chainloader
|
||||
dir_exceptions := exceptions
|
||||
dir_arm9_exceptions := $(dir_exceptions)/arm9
|
||||
dir_sysmodules := sysmodules
|
||||
dir_loader := $(dir_sysmodules)/loader
|
||||
dir_rosalina := $(dir_sysmodules)/rosalina
|
||||
dir_build := build
|
||||
dir_mset := CakeHax
|
||||
dir_out := out
|
||||
dir_emu := emunand
|
||||
dir_reboot := reboot
|
||||
dir_ninjhax := CakeBrah
|
||||
|
||||
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2
|
||||
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) --no-print-directory
|
||||
ASFLAGS := -mcpu=arm946e-s
|
||||
CFLAGS := -Wall -Wextra $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostartfiles -Wl,--nmagic
|
||||
|
||||
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||
|
||||
bundled = $(dir_build)/reboot.bin.o $(dir_build)/emunand.bin.o $(dir_build)/mmuHook.bin.o $(dir_build)/k11MainHook.bin.o $(dir_build)/svcConnectToPortInitHook.bin.o $(dir_build)/svcCustomBackdoor.bin.o\
|
||||
$(dir_build)/chainloader.bin.o $(dir_build)/arm9_exceptions.bin.o
|
||||
|
||||
modules = $(dir_build)/loader.cxi $(dir_build)/rosalina.cxi
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
endef
|
||||
|
||||
.PHONY: all
|
||||
all: launcher a9lh emunand reboot ninjhax
|
||||
all: firm
|
||||
|
||||
.PHONY: launcher
|
||||
launcher: $(dir_out)/$(name).dat
|
||||
.PHONY: release
|
||||
release: $(dir_out)/$(name)$(revision).7z
|
||||
|
||||
.PHONY: a9lh
|
||||
a9lh: $(dir_out)/arm9loaderhax.bin
|
||||
|
||||
.PHONY: emunand
|
||||
emunand: $(dir_out)/rei/emunand/emunand.bin
|
||||
|
||||
.PHONY: reboot
|
||||
reboot: $(dir_out)/rei/reboot/reboot.bin
|
||||
|
||||
.PHONY: ninjhax
|
||||
ninjhax: $(dir_out)/3ds/$(name)
|
||||
.PHONY: firm
|
||||
firm: $(dir_out)/boot.firm
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@$(MAKE) $(FLAGS) -C $(dir_mset) clean
|
||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
|
||||
rm -rf $(dir_out) $(dir_build)
|
||||
@$(MAKE) -C $(dir_arm11) clean
|
||||
@$(MAKE) -C $(dir_chainloader) clean
|
||||
@$(MAKE) -C $(dir_arm9_exceptions) clean
|
||||
@$(MAKE) -C $(dir_loader) clean
|
||||
@$(MAKE) -C $(dir_rosalina) clean
|
||||
@rm -rf $(dir_out) $(dir_build)
|
||||
|
||||
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)/rei
|
||||
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher
|
||||
dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
|
||||
.PRECIOUS: $(dir_build)/%.bin
|
||||
|
||||
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)/rei
|
||||
@cp -av $(dir_build)/main.bin $(dir_out)/arm9loaderhax.bin
|
||||
.PHONY: $(dir_arm11)
|
||||
.PHONY: $(dir_chainloader)
|
||||
.PHONY: $(dir_arm9_exceptions)
|
||||
.PHONY: $(dir_loader)
|
||||
.PHONY: $(dir_rosalina)
|
||||
|
||||
$(dir_out)/3ds/$(name):
|
||||
@mkdir -p "$(dir_out)/3ds/$(name)"
|
||||
@$(MAKE) $(FLAGS) -C $(dir_ninjhax)
|
||||
@mv $(dir_out)/$(name).3dsx $@
|
||||
@mv $(dir_out)/$(name).smdh $@
|
||||
$(dir_out)/$(name)$(revision).7z: all
|
||||
@mkdir -p "$(@D)"
|
||||
@7z a -mx $@ ./$(@D)/* ./$(dir_exceptions)/exception_dump_parser.py
|
||||
|
||||
$(dir_out)/rei:
|
||||
@mkdir -p "$(dir_out)/rei"
|
||||
$(dir_out)/boot.firm: $(dir_build)/modules.bin $(dir_build)/arm11.elf $(dir_build)/main.elf
|
||||
@mkdir -p "$(@D)"
|
||||
@firmtool build $@ -D $^ -A 0x1FF60000 -C XDMA XDMA NDMA
|
||||
|
||||
$(dir_out)/rei/emunand/emunand.bin: $(dir_emu)/emuCode.s
|
||||
$(dir_build)/modules.bin: $(modules)
|
||||
@mkdir -p "$(@D)"
|
||||
cat $^ > $@
|
||||
|
||||
$(dir_build)/arm11.elf: $(dir_arm11)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/main.elf: $(bundled) $(objects)
|
||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
|
||||
$(dir_build)/loader.cxi: $(dir_loader)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/rosalina.cxi: $(dir_rosalina)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/%.bin.o: $(dir_build)/%.bin
|
||||
@$(bin2o)
|
||||
|
||||
$(dir_build)/chainloader.bin: $(dir_chainloader)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/arm9_exceptions.bin: $(dir_arm9_exceptions)
|
||||
@mkdir -p "$(@D)"
|
||||
@$(MAKE) -C $<
|
||||
|
||||
$(dir_build)/%.bin: $(dir_patches)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
@armips $<
|
||||
@mkdir -p "$(dir_out)/rei/emunand"
|
||||
@mv emunand.bin $(dir_out)/rei/emunand
|
||||
|
||||
$(dir_out)/rei/reboot/reboot.bin: $(dir_reboot)/rebootCode.s
|
||||
@armips $<
|
||||
@mkdir -p "$(dir_out)/rei/reboot"
|
||||
@mv reboot.bin $(dir_out)/rei/reboot
|
||||
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||
$(dir_build)/config.o: CFLAGS += -DCONFIG_TITLE="\"$(name) $(revision) configuration\""
|
||||
$(dir_build)/patches.o: CFLAGS += -DREVISION=\"$(revision)\" -DCOMMIT_HASH="0x$(commit)"
|
||||
$(dir_build)/firm.o: $(dir_build)/modules.bin
|
||||
$(dir_build)/firm.o: CFLAGS += -DLUMA_SECTION0_SIZE="$(shell du -b $(dir_build)/modules.bin | cut -f1)"
|
||||
|
||||
$(dir_build)/main.bin: $(dir_build)/main.elf
|
||||
$(OC) -S -O binary $< $@
|
||||
$(dir_build)/bundled.h: $(bundled)
|
||||
@$(foreach f, $(bundled),\
|
||||
echo "extern const u8" `(echo $(basename $(notdir $(f))) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $@;\
|
||||
echo "extern const u32" `(echo $(basename $(notdir $(f)))| sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $@;\
|
||||
)
|
||||
|
||||
$(dir_build)/main.elf: $(objects_cfw)
|
||||
# FatFs requires libgcc for __aeabi_uidiv
|
||||
$(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c
|
||||
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/bundled.h
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.c) -mthumb -mthumb-interwork -Wno-unused-function $(OUTPUT_OPTION) $<
|
||||
|
||||
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) -mthumb -mthumb-interwork $(OUTPUT_OPTION) $<
|
||||
include $(call rwildcard, $(dir_build), *.d)
|
||||
|
||||
44
README.md
44
README.md
@@ -1,24 +1,40 @@
|
||||
# AuReiNand
|
||||
*A modification of the ReiNand custom firmware*
|
||||
# Luma3DS
|
||||
*Noob-proof (N)3DS "Custom Firmware"*
|
||||
|
||||
**Compiling:**
|
||||
## What it is
|
||||
|
||||
You'll need armips added to your Path. [HERE](https://www.dropbox.com/s/ceuv2qeqp38lpah/armips.exe?dl=0) is a pre-compiled version.
|
||||
**Luma3DS** is a program to patch the system software of (New) Nintendo 3DS handheld consoles "on the fly", adding features (such as per-game language settings and debugging capabilities for developers) and removing restrictions enforced by Nintendo (such as the region lock).
|
||||
It also allows you to run unauthorized ("homebrew") content by removing signature checks.
|
||||
To use it, you will need a console capable of running homebrew software on the ARM9 processor. We recommend [Plailect's guide](https://3ds.guide/) for details on how to get your system ready.
|
||||
|
||||
Lastly, just run Make and everything should work!
|
||||
Since Luma3DS v8.0, Luma3DS has its own in-game menu, triggerable by `L+Start+Select` (see the release notes).
|
||||
|
||||
Copy everything in 'out' folder to SD root and run!
|
||||
---
|
||||
|
||||
**Usage / Features:**
|
||||
## Compiling
|
||||
|
||||
See https://github.com/Reisyukaku/ReiNand and http://gbatemp.net/threads/reinand-mod-o3ds-n3ds-sysnand.411110
|
||||
First you need to clone the repository with: `git clone https://github.com/AuroraWright/Luma3DS.git`
|
||||
To compile, you'll need [armips](https://github.com/Kingcom/armips) and a build of a recent commit of [makerom](https://github.com/profi200/Project_CTR) added to your PATH. You'll also need to install [firmtool](https://github.com/TuxSH/firmtool), its README contains installation instructions.
|
||||
For now, you'll also need to update your [libctru](https://github.com/smealum/ctrulib) install, building from the latest commit.
|
||||
For your convenience, here are [Windows](http://www91.zippyshare.com/v/ePGpjk9r/file.html) and [Linux](https://mega.nz/#!uQ1T1IAD!Q91O0e12LXKiaXh_YjXD3D5m8_W3FuMI-hEa6KVMRDQ) builds of armips (thanks to who compiled them!).
|
||||
Finally just run `make` and everything should work!
|
||||
You can find the compiled files in the `out` folder.
|
||||
|
||||
The FIRMs you need are here:
|
||||
---
|
||||
|
||||
http://www99.zippyshare.com/v/kEIiQl0x/file.html
|
||||
## Setup / Usage / Features
|
||||
|
||||
**Credits:**
|
||||
|
||||
Rei as this is 99% his code (this is no more than a mod)
|
||||
See https://github.com/AuroraWright/Luma3DS/wiki
|
||||
|
||||
Everyone he credited on his GitHub :P
|
||||
---
|
||||
|
||||
## Credits
|
||||
|
||||
See https://github.com/AuroraWright/Luma3DS/wiki/Credits
|
||||
|
||||
---
|
||||
|
||||
## Licensing
|
||||
|
||||
This software is licensed under the terms of the GPLv3.
|
||||
You can find a copy of the license in the LICENSE.txt file.
|
||||
|
||||
39
arm11/Makefile
Normal file
39
arm11/Makefile
Normal file
@@ -0,0 +1,39 @@
|
||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := $(shell basename $(CURDIR))
|
||||
|
||||
dir_source := source
|
||||
dir_build := build
|
||||
dir_out := ../$(dir_build)
|
||||
|
||||
ASFLAGS := -mcpu=mpcore
|
||||
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostartfiles -Wl,--nmagic
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||
|
||||
.PHONY: all
|
||||
all: $(dir_out)/$(name).elf
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
$(dir_out)/$(name).elf: $(objects)
|
||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
16
arm11/linker.ld
Normal file
16
arm11/linker.ld
Normal file
@@ -0,0 +1,16 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x1FF80000;
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(4); }
|
||||
.bss : ALIGN(8) { __bss_start = .; *(.bss* COMMON); . = ALIGN(8); __bss_end = .; }
|
||||
|
||||
__stack_top__ = 0x1FFFF000;
|
||||
. = ALIGN(4);
|
||||
}
|
||||
207
arm11/source/main.c
Normal file
207
arm11/source/main.c
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others
|
||||
* LCD deinit code by tiniVi
|
||||
*/
|
||||
|
||||
#include "types.h"
|
||||
#include "memory.h"
|
||||
|
||||
void prepareForFirmlaunch(void);
|
||||
extern u32 prepareForFirmlaunchSize;
|
||||
|
||||
extern volatile Arm11Operation operation;
|
||||
|
||||
static void initScreensSequence(u32 brightnessLevel)
|
||||
{
|
||||
*(vu32 *)0x10141200 = 0x1007F;
|
||||
*(vu32 *)0x10202014 = 0x00000001;
|
||||
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
*(vu32 *)0x10202244 = 0x1023E;
|
||||
*(vu32 *)0x10202A44 = 0x1023E;
|
||||
|
||||
//Top screen
|
||||
*(vu32 *)0x10400400 = 0x000001c2;
|
||||
*(vu32 *)0x10400404 = 0x000000d1;
|
||||
*(vu32 *)0x10400408 = 0x000001c1;
|
||||
*(vu32 *)0x1040040c = 0x000001c1;
|
||||
*(vu32 *)0x10400410 = 0x00000000;
|
||||
*(vu32 *)0x10400414 = 0x000000cf;
|
||||
*(vu32 *)0x10400418 = 0x000000d1;
|
||||
*(vu32 *)0x1040041c = 0x01c501c1;
|
||||
*(vu32 *)0x10400420 = 0x00010000;
|
||||
*(vu32 *)0x10400424 = 0x0000019d;
|
||||
*(vu32 *)0x10400428 = 0x00000002;
|
||||
*(vu32 *)0x1040042c = 0x00000192;
|
||||
*(vu32 *)0x10400430 = 0x00000192;
|
||||
*(vu32 *)0x10400434 = 0x00000192;
|
||||
*(vu32 *)0x10400438 = 0x00000001;
|
||||
*(vu32 *)0x1040043c = 0x00000002;
|
||||
*(vu32 *)0x10400440 = 0x01960192;
|
||||
*(vu32 *)0x10400444 = 0x00000000;
|
||||
*(vu32 *)0x10400448 = 0x00000000;
|
||||
*(vu32 *)0x1040045C = 0x00f00190;
|
||||
*(vu32 *)0x10400460 = 0x01c100d1;
|
||||
*(vu32 *)0x10400464 = 0x01920002;
|
||||
*(vu32 *)0x10400468 = 0x18300000;
|
||||
*(vu32 *)0x10400470 = 0x80341;
|
||||
*(vu32 *)0x10400474 = 0x00010501;
|
||||
*(vu32 *)0x10400478 = 0;
|
||||
*(vu32 *)0x10400490 = 0x000002D0;
|
||||
*(vu32 *)0x1040049C = 0x00000000;
|
||||
|
||||
//Disco register
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
*(vu32 *)0x10400484 = 0x10101 * i;
|
||||
|
||||
//Bottom screen
|
||||
*(vu32 *)0x10400500 = 0x000001c2;
|
||||
*(vu32 *)0x10400504 = 0x000000d1;
|
||||
*(vu32 *)0x10400508 = 0x000001c1;
|
||||
*(vu32 *)0x1040050c = 0x000001c1;
|
||||
*(vu32 *)0x10400510 = 0x000000cd;
|
||||
*(vu32 *)0x10400514 = 0x000000cf;
|
||||
*(vu32 *)0x10400518 = 0x000000d1;
|
||||
*(vu32 *)0x1040051c = 0x01c501c1;
|
||||
*(vu32 *)0x10400520 = 0x00010000;
|
||||
*(vu32 *)0x10400524 = 0x0000019d;
|
||||
*(vu32 *)0x10400528 = 0x00000052;
|
||||
*(vu32 *)0x1040052c = 0x00000192;
|
||||
*(vu32 *)0x10400530 = 0x00000192;
|
||||
*(vu32 *)0x10400534 = 0x0000004f;
|
||||
*(vu32 *)0x10400538 = 0x00000050;
|
||||
*(vu32 *)0x1040053c = 0x00000052;
|
||||
*(vu32 *)0x10400540 = 0x01980194;
|
||||
*(vu32 *)0x10400544 = 0x00000000;
|
||||
*(vu32 *)0x10400548 = 0x00000011;
|
||||
*(vu32 *)0x1040055C = 0x00f00140;
|
||||
*(vu32 *)0x10400560 = 0x01c100d1;
|
||||
*(vu32 *)0x10400564 = 0x01920052;
|
||||
*(vu32 *)0x10400568 = 0x18300000 + 0x46500;
|
||||
*(vu32 *)0x10400570 = 0x80301;
|
||||
*(vu32 *)0x10400574 = 0x00010501;
|
||||
*(vu32 *)0x10400578 = 0;
|
||||
*(vu32 *)0x10400590 = 0x000002D0;
|
||||
*(vu32 *)0x1040059C = 0x00000000;
|
||||
|
||||
//Disco register
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
*(vu32 *)0x10400584 = 0x10101 * i;
|
||||
}
|
||||
|
||||
static void setupFramebuffers(struct fb *fbs)
|
||||
{
|
||||
*(vu32 *)0x10400468 = (u32)fbs[0].top_left;
|
||||
*(vu32 *)0x1040046c = (u32)fbs[1].top_left;
|
||||
*(vu32 *)0x10400494 = (u32)fbs[0].top_right;
|
||||
*(vu32 *)0x10400498 = (u32)fbs[1].top_right;
|
||||
*(vu32 *)0x10400568 = (u32)fbs[0].bottom;
|
||||
*(vu32 *)0x1040056c = (u32)fbs[1].bottom;
|
||||
}
|
||||
|
||||
static void clearScreens(struct fb *fb)
|
||||
{
|
||||
//Setting up two simultaneous memory fills using the GPU
|
||||
|
||||
vu32 *REGs_PSC0 = (vu32 *)0x10400010,
|
||||
*REGs_PSC1 = (vu32 *)0x10400020;
|
||||
|
||||
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address
|
||||
REGs_PSC0[1] = (u32)(fb->top_left + SCREEN_TOP_FBSIZE) >> 3; //End address
|
||||
REGs_PSC0[2] = 0; //Fill value
|
||||
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address
|
||||
REGs_PSC1[1] = (u32)(fb->bottom + SCREEN_BOTTOM_FBSIZE) >> 3; //End address
|
||||
REGs_PSC1[2] = 0; //Fill value
|
||||
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
|
||||
|
||||
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
|
||||
}
|
||||
|
||||
static void swapFramebuffers(bool isAlternate)
|
||||
{
|
||||
u32 isAlternateTmp = isAlternate ? 1 : 0;
|
||||
*(vu32 *)0x10400478 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp;
|
||||
*(vu32 *)0x10400578 = (*(vu32 *)0x10400478 & 0xFFFFFFFE) | isAlternateTmp;
|
||||
}
|
||||
|
||||
static void updateBrightness(u32 brightnessLevel)
|
||||
{
|
||||
//Change brightness
|
||||
*(vu32 *)0x10202240 = brightnessLevel;
|
||||
*(vu32 *)0x10202A40 = brightnessLevel;
|
||||
}
|
||||
|
||||
static void deinitScreens(void)
|
||||
{
|
||||
//Shutdown LCDs
|
||||
*(vu32 *)0x10202A44 = 0;
|
||||
*(vu32 *)0x10202244 = 0;
|
||||
*(vu32 *)0x10202014 = 0;
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
operation = ARM11_READY;
|
||||
|
||||
while(true)
|
||||
{
|
||||
switch(operation)
|
||||
{
|
||||
case ARM11_READY:
|
||||
continue;
|
||||
case INIT_SCREENS_SEQUENCE:
|
||||
initScreensSequence(*(vu32 *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case SETUP_FRAMEBUFFERS:
|
||||
setupFramebuffers((struct fb *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case CLEAR_SCREENS:
|
||||
clearScreens((struct fb *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case SWAP_FRAMEBUFFERS:
|
||||
swapFramebuffers(*(volatile bool *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case UPDATE_BRIGHTNESS:
|
||||
updateBrightness(*(vu32 *)ARM11_PARAMETERS_ADDRESS);
|
||||
break;
|
||||
case DEINIT_SCREENS:
|
||||
deinitScreens();
|
||||
break;
|
||||
case PREPARE_ARM11_FOR_FIRMLAUNCH:
|
||||
memcpy((void *)0x1FFFFC00, (void *)prepareForFirmlaunch, prepareForFirmlaunchSize);
|
||||
*(vu32 *)0x1FFFFFFC = 0;
|
||||
((void (*)(u32, volatile Arm11Operation *))0x1FFFFC00)(ARM11_READY, &operation);
|
||||
}
|
||||
|
||||
operation = ARM11_READY;
|
||||
}
|
||||
}
|
||||
56
arm11/source/memory.c
Normal file
56
arm11/source/memory.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
void memcpy(void *dest, const void *src, u32 size)
|
||||
{
|
||||
u8 *destc = (u8 *)dest;
|
||||
const u8 *srcc = (const u8 *)src;
|
||||
|
||||
for(u32 i = 0; i < size; i++)
|
||||
destc[i] = srcc[i];
|
||||
}
|
||||
|
||||
void memset(void *dest, u32 filler, u32 size)
|
||||
{
|
||||
u8 *destc = (u8 *)dest;
|
||||
|
||||
for(u32 i = 0; i < size; i++)
|
||||
destc[i] = (u8)filler;
|
||||
}
|
||||
|
||||
void memset32(void *dest, u32 filler, u32 size)
|
||||
{
|
||||
u32 *dest32 = (u32 *)dest;
|
||||
|
||||
for(u32 i = 0; i < size / 4; i++)
|
||||
dest32[i] = filler;
|
||||
}
|
||||
37
arm11/source/memory.h
Normal file
37
arm11/source/memory.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void memcpy(void *dest, const void *src, u32 size);
|
||||
void memset(void *dest, u32 value, u32 size) __attribute__((used));
|
||||
void memset32(void *dest, u32 filler, u32 size);
|
||||
81
arm11/source/start.s
Normal file
81
arm11/source/start.s
Normal file
@@ -0,0 +1,81 @@
|
||||
@ This file is part of Luma3DS
|
||||
@ Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
@ * Requiring preservation of specified reasonable legal notices or
|
||||
@ author attributions in that material or in the Appropriate Legal
|
||||
@ Notices displayed by works containing it.
|
||||
@ * Prohibiting misrepresentation of the origin of that material,
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
|
||||
.section .text.start
|
||||
.align 4
|
||||
.global _start
|
||||
.type _start, %function
|
||||
_start:
|
||||
b start
|
||||
|
||||
.global operation
|
||||
operation:
|
||||
.word 0
|
||||
|
||||
start:
|
||||
@ Disable interrupts and switch to supervisor mode
|
||||
cpsid aif, #0x13
|
||||
|
||||
@ Set the control register to reset default: everything disabled
|
||||
ldr r0, =0x54078
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
@ Set the auxiliary control register to reset default.
|
||||
@ Enables instruction folding, static branch prediction,
|
||||
@ dynamic branch prediction, and return stack.
|
||||
mov r0, #0xF
|
||||
mcr p15, 0, r0, c1, c0, 1
|
||||
|
||||
@ Invalidate both caches, flush the prefetch buffer then DSB
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 4
|
||||
mcr p15, 0, r0, c7, c7, 0
|
||||
mcr p15, 0, r0, c7, c10, 4
|
||||
|
||||
@ Clear BSS
|
||||
ldr r0, =__bss_start
|
||||
mov r1, #0
|
||||
ldr r2, =__bss_end
|
||||
sub r2, r0
|
||||
bl memset32
|
||||
|
||||
ldr sp, =__stack_top__
|
||||
b main
|
||||
|
||||
.global prepareForFirmlaunch
|
||||
.type prepareForFirmlaunch, %function
|
||||
prepareForFirmlaunch:
|
||||
str r0, [r1] @ tell ARM9 we're done
|
||||
mov r0, #0x20000000
|
||||
|
||||
_wait_for_core0_entrypoint_loop:
|
||||
ldr r1, [r0, #-4] @ check if core0's entrypoint is 0
|
||||
cmp r1, #0
|
||||
beq _wait_for_core0_entrypoint_loop
|
||||
|
||||
bx r1 @ jump to core0's entrypoint
|
||||
prepareForFirmlaunchEnd:
|
||||
|
||||
.global prepareForFirmlaunchSize
|
||||
prepareForFirmlaunchSize: .word prepareForFirmlaunchEnd - prepareForFirmlaunch
|
||||
65
arm11/source/types.h
Normal file
65
arm11/source/types.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
//Common data types
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef volatile u8 vu8;
|
||||
typedef volatile u16 vu16;
|
||||
typedef volatile u32 vu32;
|
||||
typedef volatile u64 vu64;
|
||||
|
||||
#define SCREEN_TOP_WIDTH 400
|
||||
#define SCREEN_BOTTOM_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
|
||||
#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
|
||||
#define ARM11_PARAMETERS_ADDRESS 0x1FFFF000
|
||||
|
||||
struct fb {
|
||||
u8 *top_left;
|
||||
u8 *top_right;
|
||||
u8 *bottom;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INIT_SCREENS_SEQUENCE = 0,
|
||||
SETUP_FRAMEBUFFERS,
|
||||
CLEAR_SCREENS,
|
||||
SWAP_FRAMEBUFFERS,
|
||||
UPDATE_BRIGHTNESS,
|
||||
DEINIT_SCREENS,
|
||||
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
||||
ARM11_READY,
|
||||
} Arm11Operation;
|
||||
44
chainloader/Makefile
Normal file
44
chainloader/Makefile
Normal file
@@ -0,0 +1,44 @@
|
||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := $(shell basename $(CURDIR))
|
||||
|
||||
dir_source := source
|
||||
dir_build := build
|
||||
dir_out := ../$(dir_build)
|
||||
|
||||
ASFLAGS := -mcpu=arm946e-s
|
||||
CFLAGS := -Wall -Wextra -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostartfiles -Wl,--nmagic
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||
|
||||
.PHONY: all
|
||||
all: $(dir_out)/$(name).bin
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(dir_build)/$(name).elf: $(objects)
|
||||
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
|
||||
$(dir_build)/memory.o: CFLAGS += -O3
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
21
chainloader/linker.ld
Normal file
21
chainloader/linker.ld
Normal file
@@ -0,0 +1,21 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x01FF9000;
|
||||
|
||||
__start__ = ABSOLUTE(.);
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
||||
|
||||
. = ALIGN(4);
|
||||
|
||||
__end__ = ABSOLUTE(.);
|
||||
|
||||
__stack_top__ = 0x01FFB800;
|
||||
__stack_bottom__ = 0x01FFA800;
|
||||
}
|
||||
31
chainloader/source/cache.h
Normal file
31
chainloader/source/cache.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void flushCaches(void);
|
||||
60
chainloader/source/cache.s
Normal file
60
chainloader/source/cache.s
Normal file
@@ -0,0 +1,60 @@
|
||||
@ This file is part of Luma3DS
|
||||
@ Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
@ * Requiring preservation of specified reasonable legal notices or
|
||||
@ author attributions in that material or in the Appropriate Legal
|
||||
@ Notices displayed by works containing it.
|
||||
@ * Prohibiting misrepresentation of the origin of that material,
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
|
||||
.text
|
||||
.arm
|
||||
.align 4
|
||||
|
||||
.global flushCaches
|
||||
.type flushCaches, %function
|
||||
flushCaches:
|
||||
@ Clean and flush both the data cache and instruction caches
|
||||
|
||||
@ Adpated from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html ,
|
||||
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
|
||||
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
|
||||
|
||||
@ Implemented in bootROM at addresses 0xffff0830 (DCache) and 0xffff0ab4 (ICache)
|
||||
|
||||
mov r1, #0 @ segment counter
|
||||
outer_loop:
|
||||
mov r0, #0 @ line counter
|
||||
|
||||
inner_loop:
|
||||
orr r2, r1, r0 @ generate segment and line address
|
||||
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
|
||||
add r0, #0x20 @ increment to next line
|
||||
cmp r0, #0x400
|
||||
bne inner_loop
|
||||
|
||||
add r1, #0x40000000
|
||||
cmp r1, #0
|
||||
bne outer_loop
|
||||
|
||||
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
|
||||
|
||||
@ Flush instruction cache
|
||||
mcr p15, 0, r1, c7, c5, 0
|
||||
|
||||
bx lr
|
||||
42
chainloader/source/firm.c
Normal file
42
chainloader/source/firm.c
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "firm.h"
|
||||
#include "memory.h"
|
||||
#include "cache.h"
|
||||
|
||||
void disableMpuAndJumpToEntrypoints(int argc, char **argv, void *arm11Entry, void *arm9Entry);
|
||||
|
||||
void launchFirm(Firm *firm, int argc, char **argv)
|
||||
{
|
||||
//Copy FIRM sections to respective memory locations
|
||||
for(u32 sectionNum = 0; sectionNum < 4; sectionNum++)
|
||||
memcpy(firm->section[sectionNum].address, (u8 *)firm + firm->section[sectionNum].offset, firm->section[sectionNum].size);
|
||||
|
||||
disableMpuAndJumpToEntrypoints(argc, argv, firm->arm9Entry, firm->arm11Entry);
|
||||
|
||||
__builtin_unreachable();
|
||||
}
|
||||
50
chainloader/source/firm.h
Normal file
50
chainloader/source/firm.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u32 offset;
|
||||
u8 *address;
|
||||
u32 size;
|
||||
u32 procType;
|
||||
u8 hash[0x20];
|
||||
} FirmSection;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
char magic[4];
|
||||
u32 reserved1;
|
||||
u8 *arm11Entry;
|
||||
u8 *arm9Entry;
|
||||
u8 reserved2[0x30];
|
||||
FirmSection section[4];
|
||||
} Firm;
|
||||
|
||||
void launchFirm(Firm *firm, int argc, char **argv);
|
||||
59
chainloader/source/main.c
Normal file
59
chainloader/source/main.c
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
#include "cache.h"
|
||||
#include "firm.h"
|
||||
|
||||
void main(int argc, char **argv)
|
||||
{
|
||||
Firm *firm = (Firm *)0x20001000;
|
||||
char *argvPassed[2],
|
||||
absPath[24 + 255];
|
||||
struct fb fbs[2];
|
||||
|
||||
if(argc > 0)
|
||||
{
|
||||
u32 i;
|
||||
for(i = 0; i < sizeof(absPath) - 1 && argv[0][i] != 0; i++)
|
||||
absPath[i] = argv[0][i];
|
||||
absPath[i] = 0;
|
||||
|
||||
argvPassed[0] = (char *)absPath;
|
||||
}
|
||||
|
||||
if(argc == 2)
|
||||
{
|
||||
struct fb *fbsrc = (struct fb *)argv[1];
|
||||
|
||||
fbs[0] = fbsrc[0];
|
||||
fbs[1] = fbsrc[1];
|
||||
|
||||
argvPassed[1] = (char *)&fbs;
|
||||
}
|
||||
|
||||
launchFirm(firm, argc, argvPassed);
|
||||
}
|
||||
40
chainloader/source/memory.c
Normal file
40
chainloader/source/memory.c
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
void memcpy(void *dest, const void *src, u32 size)
|
||||
{
|
||||
u8 *destc = (u8 *)dest;
|
||||
const u8 *srcc = (const u8 *)src;
|
||||
|
||||
for(u32 i = 0; i < size; i++)
|
||||
destc[i] = srcc[i];
|
||||
}
|
||||
35
chainloader/source/memory.h
Normal file
35
chainloader/source/memory.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* memcpy adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void memcpy(void *dest, const void *src, u32 size);
|
||||
60
chainloader/source/start.s
Normal file
60
chainloader/source/start.s
Normal file
@@ -0,0 +1,60 @@
|
||||
@ This file is part of Luma3DS
|
||||
@ Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
@ * Requiring preservation of specified reasonable legal notices or
|
||||
@ author attributions in that material or in the Appropriate Legal
|
||||
@ Notices displayed by works containing it.
|
||||
@ * Prohibiting misrepresentation of the origin of that material,
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
.arm
|
||||
|
||||
.section .text.start
|
||||
.align 4
|
||||
.global _start
|
||||
_start:
|
||||
ldr sp, =__stack_top__
|
||||
b main
|
||||
|
||||
.text
|
||||
.balign 4
|
||||
.global disableMpuAndJumpToEntrypoints
|
||||
.type disableMpuAndJumpToEntrypoints, %function
|
||||
disableMpuAndJumpToEntrypoints:
|
||||
mov r4, r0
|
||||
mov r5, r1
|
||||
mov r6, r2
|
||||
mov r7, r3
|
||||
|
||||
bl flushCaches
|
||||
|
||||
@ Disable caches / MPU
|
||||
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
||||
bic r0, #(1<<12) @ - instruction cache disable
|
||||
bic r0, #(1<<2) @ - data cache disable
|
||||
bic r0, #(1<<0) @ - MPU disable
|
||||
mcr p15, 0, r0, c1, c0, 0 @ write control register
|
||||
|
||||
@ Set the ARM11 entrypoint
|
||||
mov r0, #0x20000000
|
||||
str r7, [r0, #-4]
|
||||
|
||||
@ Jump to the ARM9 entrypoint
|
||||
mov r0, r4
|
||||
mov r1, r5
|
||||
ldr r2, =0x1BEEF
|
||||
bx r6
|
||||
45
chainloader/source/types.h
Normal file
45
chainloader/source/types.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
//Common data types
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef volatile u8 vu8;
|
||||
typedef volatile u16 vu16;
|
||||
typedef volatile u32 vu32;
|
||||
typedef volatile u64 vu64;
|
||||
|
||||
struct fb {
|
||||
u8 *top_left;
|
||||
u8 *top_right;
|
||||
u8 *bottom;
|
||||
} __attribute__((packed));
|
||||
@@ -1,50 +0,0 @@
|
||||
.nds
|
||||
|
||||
sdmmc equ 0x434D4453 ;dummy
|
||||
|
||||
.create "emunand.bin", 0x0801A5C0
|
||||
.org 0x0801A5C0
|
||||
.arm
|
||||
nand_sd:
|
||||
; Original code that still needs to be executed.
|
||||
mov r4, r0
|
||||
mov r5, r1
|
||||
mov r7, r2
|
||||
mov r6, r3
|
||||
; End.
|
||||
|
||||
; If we're already trying to access the SD, return.
|
||||
ldr r2, [r0, #4]
|
||||
ldr r1, =sdmmc
|
||||
cmp r2, r1
|
||||
beq nand_sd_ret
|
||||
|
||||
str r1, [r0, #4] ; Set object to be SD
|
||||
ldr r2, [r0, #8] ; Get sector to read
|
||||
cmp r2, #0 ; For GW compatibility, see if we're trying to read the ncsd header (sector 0)
|
||||
|
||||
ldr r3, =nand_offset
|
||||
ldr r3, [r3]
|
||||
add r2, r3 ; Add the offset to the NAND in the SD.
|
||||
|
||||
ldreq r3, =ncsd_header_offset
|
||||
ldreq r3, [r3]
|
||||
addeq r2, r3 ; If we're reading the ncsd header, add the offset of that sector.
|
||||
|
||||
str r2, [r0, #8] ; Store sector to read
|
||||
|
||||
nand_sd_ret:
|
||||
; Restore registers.
|
||||
mov r1, r5
|
||||
mov r2, r7
|
||||
mov r3, r6
|
||||
|
||||
; Return 4 bytes behind where we got called,
|
||||
; due to the offset of this function being stored there.
|
||||
mov r0, lr
|
||||
add r0, #4
|
||||
bx r0
|
||||
.pool
|
||||
nand_offset: .ascii "NAND" ; for rednand this should be 1
|
||||
ncsd_header_offset: .ascii "NCSD" ; depends on nand manufacturer + emunand type (GW/RED)
|
||||
.close
|
||||
42
exceptions/arm9/Makefile
Normal file
42
exceptions/arm9/Makefile
Normal file
@@ -0,0 +1,42 @@
|
||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/base_tools
|
||||
|
||||
name := arm9_exceptions
|
||||
|
||||
dir_source := source
|
||||
dir_build := build
|
||||
dir_out := ../../$(dir_build)
|
||||
|
||||
ASFLAGS := -mcpu=arm946e-s
|
||||
CFLAGS := -Wall -Wextra -mthumb $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math
|
||||
LDFLAGS := -nostdlib
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
|
||||
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c)))
|
||||
|
||||
.PHONY: all
|
||||
all: $(dir_out)/$(name).bin
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
$(dir_out)/$(name).bin: $(dir_build)/$(name).elf
|
||||
$(OBJCOPY) -S -O binary $< $@
|
||||
|
||||
$(dir_build)/$(name).elf: $(objects)
|
||||
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
14
exceptions/arm9/linker.ld
Normal file
14
exceptions/arm9/linker.ld
Normal file
@@ -0,0 +1,14 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x01FF7FE0;
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(8); *(.bss* COMMON); . = ALIGN(8); }
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
||||
50
exceptions/arm9/source/handlers.h
Normal file
50
exceptions/arm9/source/handlers.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u32 magic[2];
|
||||
u16 versionMinor, versionMajor;
|
||||
|
||||
u16 processor, core;
|
||||
u32 type;
|
||||
|
||||
u32 totalSize;
|
||||
u32 registerDumpSize;
|
||||
u32 codeDumpSize;
|
||||
u32 stackDumpSize;
|
||||
u32 additionalDataSize;
|
||||
} ExceptionDumpHeader;
|
||||
|
||||
u32 readMPUConfig(u32 *regionSettings);
|
||||
void FIQHandler(void);
|
||||
void undefinedInstructionHandler(void);
|
||||
void dataAbortHandler(void);
|
||||
void prefetchAbortHandler(void);
|
||||
113
exceptions/arm9/source/handlers.s
Normal file
113
exceptions/arm9/source/handlers.s
Normal file
@@ -0,0 +1,113 @@
|
||||
@ This file is part of Luma3DS
|
||||
@ Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
@ * Requiring preservation of specified reasonable legal notices or
|
||||
@ author attributions in that material or in the Appropriate Legal
|
||||
@ Notices displayed by works containing it.
|
||||
@ * Prohibiting misrepresentation of the origin of that material,
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
|
||||
.macro GEN_HANDLER name
|
||||
.global \name
|
||||
.type \name, %function
|
||||
\name:
|
||||
ldr sp, =#0x02000000 @ We make the (full descending) stack point to the end of ITCM for our exception handlers.
|
||||
@ It doesn't matter if we're overwriting stuff here, since we're going to reboot.
|
||||
|
||||
stmfd sp!, {r0-r7} @ FIQ has its own r8-r14 regs
|
||||
ldr r1, =\@ @ macro expansion counter
|
||||
b _commonHandler
|
||||
|
||||
.size \name, . - \name
|
||||
.endm
|
||||
|
||||
.text
|
||||
.arm
|
||||
.align 4
|
||||
|
||||
.global _commonHandler
|
||||
.type _commonHandler, %function
|
||||
_commonHandler:
|
||||
mrs r2, spsr
|
||||
mov r6, sp
|
||||
mrs r3, cpsr
|
||||
|
||||
orr r3, #0x1c0 @ disable Imprecise Aborts, IRQ and FIQ (equivalent to "cpsid aif" on arm11)
|
||||
msr cpsr_cx, r3
|
||||
|
||||
tst r2, #0x20
|
||||
bne noSvcBreak
|
||||
cmp r1, #2
|
||||
bne noSvcBreak
|
||||
|
||||
sub r0, lr, #4 @ calling cannotAccessAddress cause more problems that it actually solves... (I've to save a lot of regs and that's a pain tbh)
|
||||
lsr r0, #20 @ we'll just do some address checks (to see if it's in ARM9 internal memory)
|
||||
cmp r0, #0x80
|
||||
bne noSvcBreak
|
||||
ldr r4, [lr, #-4]
|
||||
ldr r5, =#0xe12fff7f
|
||||
cmp r4, r5
|
||||
bne noSvcBreak
|
||||
bic r5, r3, #0xf
|
||||
orr r5, #0x3
|
||||
msr cpsr_c, r5 @ switch to supervisor mode
|
||||
ldmfd sp, {r8-r11}^
|
||||
ldr r2, [sp, #0x1c] @ implementation details of the official svc handler
|
||||
ldr r4, [sp, #0x18]
|
||||
msr cpsr_c, r3 @ restore processor mode
|
||||
tst r2, #0x20
|
||||
addne lr, r4, #2 @ adjust address for later
|
||||
moveq lr, r4
|
||||
|
||||
noSvcBreak:
|
||||
ands r4, r2, #0xf @ get the mode that triggered the exception
|
||||
moveq r4, #0xf @ usr => sys
|
||||
bic r5, r3, #0xf
|
||||
orr r5, r4
|
||||
msr cpsr_c, r5 @ change processor mode
|
||||
stmfd r6!, {r8-lr}
|
||||
msr cpsr_c, r3 @ restore processor mode
|
||||
mov sp, r6
|
||||
|
||||
stmfd sp!, {r2,lr} @ it's a bit of a mess, but we will fix that later
|
||||
@ order of saved regs now: cpsr, pc + (2/4/8), r8-r14, r0-r7
|
||||
|
||||
mov r0, sp
|
||||
|
||||
b mainHandler
|
||||
|
||||
GEN_HANDLER FIQHandler
|
||||
GEN_HANDLER undefinedInstructionHandler
|
||||
GEN_HANDLER prefetchAbortHandler
|
||||
GEN_HANDLER dataAbortHandler
|
||||
|
||||
.global readMPUConfig
|
||||
.type readMPUConfig, %function
|
||||
readMPUConfig:
|
||||
stmfd sp!, {r4-r8, lr}
|
||||
mrc p15,0,r1,c6,c0,0
|
||||
mrc p15,0,r2,c6,c1,0
|
||||
mrc p15,0,r3,c6,c2,0
|
||||
mrc p15,0,r4,c6,c3,0
|
||||
mrc p15,0,r5,c6,c4,0
|
||||
mrc p15,0,r6,c6,c5,0
|
||||
mrc p15,0,r7,c6,c6,0
|
||||
mrc p15,0,r8,c6,c7,0
|
||||
stmia r0, {r1-r8}
|
||||
mrc p15,0,r0,c5,c0,2 @ read data access permission bits
|
||||
ldmfd sp!, {r4-r8, pc}
|
||||
143
exceptions/arm9/source/i2c.c
Normal file
143
exceptions/arm9/source/i2c.c
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Thanks to whoever contributed in the development of this file
|
||||
*/
|
||||
|
||||
#include "i2c.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const struct { u8 bus_id, reg_addr; } dev_data[] = {
|
||||
{0, 0x4A}, {0, 0x7A}, {0, 0x78},
|
||||
{1, 0x4A}, {1, 0x78}, {1, 0x2C},
|
||||
{1, 0x2E}, {1, 0x40}, {1, 0x44},
|
||||
{2, 0xD6}, {2, 0xD0}, {2, 0xD2},
|
||||
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
||||
};
|
||||
|
||||
static inline u8 i2cGetDeviceBusId(u8 device_id)
|
||||
{
|
||||
return dev_data[device_id].bus_id;
|
||||
}
|
||||
|
||||
static inline u8 i2cGetDeviceRegAddr(u8 device_id)
|
||||
{
|
||||
return dev_data[device_id].reg_addr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static vu8 *reg_data_addrs[] = {
|
||||
(vu8 *)(I2C1_REG_OFF + I2C_REG_DATA),
|
||||
(vu8 *)(I2C2_REG_OFF + I2C_REG_DATA),
|
||||
(vu8 *)(I2C3_REG_OFF + I2C_REG_DATA),
|
||||
};
|
||||
|
||||
static inline vu8 *i2cGetDataReg(u8 bus_id)
|
||||
{
|
||||
return reg_data_addrs[bus_id];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static vu8 *reg_cnt_addrs[] = {
|
||||
(vu8 *)(I2C1_REG_OFF + I2C_REG_CNT),
|
||||
(vu8 *)(I2C2_REG_OFF + I2C_REG_CNT),
|
||||
(vu8 *)(I2C3_REG_OFF + I2C_REG_CNT),
|
||||
};
|
||||
|
||||
static inline vu8 *i2cGetCntReg(u8 bus_id)
|
||||
{
|
||||
return reg_cnt_addrs[bus_id];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static inline void i2cWaitBusy(u8 bus_id)
|
||||
{
|
||||
while (*i2cGetCntReg(bus_id) & 0x80);
|
||||
}
|
||||
|
||||
static inline bool i2cGetResult(u8 bus_id)
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
|
||||
return (*i2cGetCntReg(bus_id) >> 4) & 1;
|
||||
}
|
||||
|
||||
static void i2cStop(u8 bus_id, u8 arg0)
|
||||
{
|
||||
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static bool i2cSelectDevice(u8 bus_id, u8 dev_reg)
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = dev_reg;
|
||||
*i2cGetCntReg(bus_id) = 0xC2;
|
||||
|
||||
return i2cGetResult(bus_id);
|
||||
}
|
||||
|
||||
static bool i2cSelectRegister(u8 bus_id, u8 reg)
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = reg;
|
||||
*i2cGetCntReg(bus_id) = 0xC0;
|
||||
|
||||
return i2cGetResult(bus_id);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
|
||||
{
|
||||
u8 bus_id = i2cGetDeviceBusId(dev_id);
|
||||
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||
|
||||
for(u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = data;
|
||||
*i2cGetCntReg(bus_id) = 0xC1;
|
||||
i2cStop(bus_id, 0);
|
||||
|
||||
if(i2cGetResult(bus_id)) return true;
|
||||
}
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
i2cWaitBusy(bus_id);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
48
exceptions/arm9/source/i2c.h
Normal file
48
exceptions/arm9/source/i2c.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Thanks to whoever contributed in the development of this file
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define I2C1_REG_OFF 0x10161000
|
||||
#define I2C2_REG_OFF 0x10144000
|
||||
#define I2C3_REG_OFF 0x10148000
|
||||
|
||||
#define I2C_REG_DATA 0
|
||||
#define I2C_REG_CNT 1
|
||||
#define I2C_REG_CNTEX 2
|
||||
#define I2C_REG_SCL 4
|
||||
|
||||
#define I2C_DEV_MCU 3
|
||||
#define I2C_DEV_GYRO 10
|
||||
#define I2C_DEV_IR 13
|
||||
|
||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
|
||||
122
exceptions/arm9/source/mainHandler.c
Normal file
122
exceptions/arm9/source/mainHandler.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "i2c.h"
|
||||
#include "handlers.h"
|
||||
|
||||
#define FINAL_BUFFER 0x25000000
|
||||
|
||||
#define REG_DUMP_SIZE 4 * 17
|
||||
#define CODE_DUMP_SIZE 48
|
||||
|
||||
bool cannotAccessAddress(const void *address)
|
||||
{
|
||||
u32 regionSettings[8];
|
||||
u32 addr = (u32)address;
|
||||
|
||||
u32 dataAccessPermissions = readMPUConfig(regionSettings);
|
||||
for(u32 i = 0; i < 8; i++)
|
||||
{
|
||||
if((dataAccessPermissions & 0xF) == 0 || (regionSettings[i] & 1) == 0)
|
||||
continue; //No access / region not enabled
|
||||
|
||||
u32 regionAddrBase = regionSettings[i] & ~0xFFF;
|
||||
u32 regionSize = 1 << (((regionSettings[i] >> 1) & 0x1F) + 1);
|
||||
|
||||
if(addr >= regionAddrBase && addr < regionAddrBase + regionSize)
|
||||
return false;
|
||||
|
||||
dataAccessPermissions >>= 4;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 __attribute__((noinline)) copyMemory(void *dst, const void *src, u32 size, u32 alignment)
|
||||
{
|
||||
u8 *out = (u8 *)dst;
|
||||
const u8 *in = (const u8 *)src;
|
||||
|
||||
if(((u32)src & (alignment - 1)) != 0 || cannotAccessAddress(src) || (size != 0 && cannotAccessAddress((u8 *)src + size - 1)))
|
||||
return 0;
|
||||
|
||||
for(u32 i = 0; i < size; i++)
|
||||
*out++ = *in++;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void __attribute__((noreturn)) mainHandler(u32 *regs, u32 type)
|
||||
{
|
||||
ExceptionDumpHeader dumpHeader;
|
||||
|
||||
u32 registerDump[REG_DUMP_SIZE / 4];
|
||||
u8 codeDump[CODE_DUMP_SIZE];
|
||||
|
||||
dumpHeader.magic[0] = 0xDEADC0DE;
|
||||
dumpHeader.magic[1] = 0xDEADCAFE;
|
||||
dumpHeader.versionMajor = 1;
|
||||
dumpHeader.versionMinor = 2;
|
||||
|
||||
dumpHeader.processor = 9;
|
||||
dumpHeader.core = 0;
|
||||
dumpHeader.type = type;
|
||||
|
||||
dumpHeader.registerDumpSize = REG_DUMP_SIZE;
|
||||
dumpHeader.codeDumpSize = CODE_DUMP_SIZE;
|
||||
dumpHeader.additionalDataSize = 0;
|
||||
|
||||
//Dump registers
|
||||
//Current order of saved regs: cpsr, pc, r8-r14, r0-r7
|
||||
u32 cpsr = regs[0];
|
||||
u32 pc = regs[1] - (type < 3 ? (((cpsr & 0x20) != 0 && type == 1) ? 2 : 4) : 8);
|
||||
|
||||
registerDump[15] = pc;
|
||||
registerDump[16] = cpsr;
|
||||
for(u32 i = 0; i < 7; i++) registerDump[8 + i] = regs[2 + i];
|
||||
for(u32 i = 0; i < 8; i++) registerDump[i] = regs[9 + i];
|
||||
|
||||
//Dump code
|
||||
u8 *instr = (u8 *)pc + ((cpsr & 0x20) ? 2 : 4) - dumpHeader.codeDumpSize; //Doesn't work well on 32-bit Thumb instructions, but it isn't much of a problem
|
||||
dumpHeader.codeDumpSize = copyMemory(codeDump, instr, dumpHeader.codeDumpSize, ((cpsr & 0x20) != 0) ? 2 : 4);
|
||||
|
||||
//Copy register dump and code dump
|
||||
u8 *final = (u8 *)(FINAL_BUFFER + sizeof(ExceptionDumpHeader));
|
||||
final += copyMemory(final, registerDump, dumpHeader.registerDumpSize, 1);
|
||||
final += copyMemory(final, codeDump, dumpHeader.codeDumpSize, 1);
|
||||
|
||||
//Dump stack in place
|
||||
dumpHeader.stackDumpSize = copyMemory(final, (const void *)registerDump[13], 0x1000 - (registerDump[13] & 0xFFF), 1);
|
||||
|
||||
dumpHeader.totalSize = sizeof(ExceptionDumpHeader) + dumpHeader.registerDumpSize + dumpHeader.codeDumpSize + dumpHeader.stackDumpSize + dumpHeader.additionalDataSize;
|
||||
|
||||
//Copy header (actually optimized by the compiler)
|
||||
*(ExceptionDumpHeader *)FINAL_BUFFER = dumpHeader;
|
||||
|
||||
((void (*)())0xFFFF0830)(); //Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); //Reboot
|
||||
while(true);
|
||||
}
|
||||
35
exceptions/arm9/source/start.s
Normal file
35
exceptions/arm9/source/start.s
Normal file
@@ -0,0 +1,35 @@
|
||||
@ This file is part of Luma3DS
|
||||
@ Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
@ * Requiring preservation of specified reasonable legal notices or
|
||||
@ author attributions in that material or in the Appropriate Legal
|
||||
@ Notices displayed by works containing it.
|
||||
@ * Prohibiting misrepresentation of the origin of that material,
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
|
||||
.section .text.start
|
||||
.align 4
|
||||
.global _start
|
||||
_start:
|
||||
add pc, r0, #(handlers - .) @ Dummy instruction to prevent compiler optimizations
|
||||
|
||||
handlers:
|
||||
.word FIQHandler
|
||||
.word undefinedInstructionHandler
|
||||
.word prefetchAbortHandler
|
||||
.word dataAbortHandler
|
||||
41
exceptions/arm9/source/types.h
Normal file
41
exceptions/arm9/source/types.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
//Common data types
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef volatile u8 vu8;
|
||||
typedef volatile u16 vu16;
|
||||
typedef volatile u32 vu32;
|
||||
typedef volatile u64 vu64;
|
||||
169
exceptions/exception_dump_parser.py
Normal file
169
exceptions/exception_dump_parser.py
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python
|
||||
# Requires Python >= 3.2 or >= 2.7
|
||||
|
||||
# This file is part of Luma3DS
|
||||
# Copyright (C) 2016 Aurora Wright, TuxSH
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
|
||||
# reasonable legal notices or author attributions in that material or in the Appropriate Legal
|
||||
# Notices displayed by works containing it.
|
||||
|
||||
__author__ = "TuxSH"
|
||||
__copyright__ = "Copyright (c) 2016 TuxSH"
|
||||
__license__ = "GPLv3"
|
||||
__version__ = "v1.2"
|
||||
|
||||
"""
|
||||
Parses Luma3DS exception dumps
|
||||
"""
|
||||
|
||||
import argparse
|
||||
from struct import unpack_from
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
# Source of hexdump: https://gist.github.com/ImmortalPC/c340564823f283fe530b
|
||||
# Credits for hexdump go to the original authors
|
||||
# Slightly edited by TuxSH
|
||||
|
||||
def hexdump(addr, src, length=16, sep='.' ):
|
||||
'''
|
||||
@brief Return {src} in hex dump.
|
||||
@param[in] length {Int} Nb Bytes by row.
|
||||
@param[in] sep {Char} For the text part, {sep} will be used for non ASCII char.
|
||||
@return {Str} The hexdump
|
||||
@note Full support for python2 and python3 !
|
||||
'''
|
||||
result = []
|
||||
|
||||
# Python3 support
|
||||
try:
|
||||
xrange(0,1)
|
||||
except NameError:
|
||||
xrange = range
|
||||
|
||||
for i in xrange(0, len(src), length):
|
||||
subSrc = src[i:i+length]
|
||||
hexa = ''
|
||||
isMiddle = False
|
||||
for h in xrange(0,len(subSrc)):
|
||||
if h == length/2:
|
||||
hexa += ' '
|
||||
h = subSrc[h]
|
||||
if not isinstance(h, int):
|
||||
h = ord(h)
|
||||
h = hex(h).replace('0x','')
|
||||
if len(h) == 1:
|
||||
h = '0'+h
|
||||
hexa += h+' '
|
||||
hexa = hexa.strip(' ')
|
||||
text = ''
|
||||
for c in subSrc:
|
||||
if not isinstance(c, int):
|
||||
c = ord(c)
|
||||
if 0x20 <= c < 0x7F:
|
||||
text += chr(c)
|
||||
else:
|
||||
text += sep
|
||||
result.append(('%08x: %-'+str(length*(2+1)+1)+'s |%s|') % (addr + i, hexa, text))
|
||||
|
||||
return '\n'.join(result)
|
||||
|
||||
|
||||
def makeRegisterLine(A, rA, B, rB):
|
||||
return "{0:<15}{1:<20}{2:<15}{3:<20}".format(A, "{0:08x}".format(rA), B, "{0:08x}".format(rB))
|
||||
|
||||
handledExceptionNames = ("FIQ", "undefined instruction", "prefetch abort", "data abort")
|
||||
registerNames = tuple("r{0}".format(i) for i in range(13)) + ("sp", "lr", "pc", "cpsr") + ("dfsr", "ifsr", "far") + ("fpexc", "fpinst", "fpinst2")
|
||||
svcBreakReasons = ("(svcBreak: panic)", "(svcBreak: assertion failed)", "(svcBreak: user-related)")
|
||||
|
||||
if __name__ == "__main__":
|
||||
parser = argparse.ArgumentParser(description="Parse Luma3DS exception dumps")
|
||||
parser.add_argument("filename")
|
||||
args = parser.parse_args()
|
||||
data = b""
|
||||
with open(args.filename, "rb") as f: data = f.read()
|
||||
if unpack_from("<2I", data) != (0xdeadc0de, 0xdeadcafe):
|
||||
raise SystemExit("Invalid file format")
|
||||
|
||||
version, processor, exceptionType, _, nbRegisters, codeDumpSize, stackDumpSize, additionalDataSize = unpack_from("<8I", data, 8)
|
||||
nbRegisters //= 4
|
||||
|
||||
if version < (1 << 16) | 2:
|
||||
raise SystemExit("Incompatible format version, please use the appropriate parser.")
|
||||
|
||||
registers = unpack_from("<{0}I".format(nbRegisters), data, 40)
|
||||
codeOffset = 40 + 4 * nbRegisters
|
||||
codeDump = data[codeOffset : codeOffset + codeDumpSize]
|
||||
stackOffset = codeOffset + codeDumpSize
|
||||
stackDump = data[stackOffset : stackOffset + stackDumpSize]
|
||||
addtionalDataOffset = stackOffset + stackDumpSize
|
||||
additionalData = data[addtionalDataOffset : addtionalDataOffset + additionalDataSize]
|
||||
|
||||
if processor == 9: print("Processor: ARM9")
|
||||
else: print("Processor: ARM11 (core {0})".format(processor >> 16))
|
||||
|
||||
typeDetailsStr = ""
|
||||
if exceptionType == 2:
|
||||
if (registers[16] & 0x20) == 0 and codeDumpSize >= 4:
|
||||
instr = unpack_from("<I", codeDump[-4:])[0]
|
||||
if instr == 0xe12fff7e:
|
||||
typeDetailsStr = " (kernel panic)"
|
||||
elif instr == 0xef00003c:
|
||||
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
||||
elif (registers[16] & 0x20) == 1 and codeDumpSize >= 2:
|
||||
instr = unpack_from("<I", codeDump[-4:])[0]
|
||||
if instr == 0xdf3c:
|
||||
typeDetailsStr = " " + (svcBreakReasons[registers[0]] if registers[0] < 3 else "(svcBreak)")
|
||||
|
||||
elif processor != 9 and (registers[20] & 0x80000000) != 0:
|
||||
typeDetailsStr = " (VFP exception)"
|
||||
|
||||
print("Exception type: {0}{1}".format("unknown" if exceptionType >= len(handledExceptionNames) else handledExceptionNames[exceptionType], typeDetailsStr))
|
||||
if additionalDataSize != 0:
|
||||
print("Current process: {0} ({1:016x})".format(additionalData[:8].decode("ascii"), unpack_from("<Q", additionalData, 8)[0]))
|
||||
|
||||
print("\nRegister dump:\n")
|
||||
for i in range(0, nbRegisters - (nbRegisters % 2), 2):
|
||||
if i == 16: print("")
|
||||
print(makeRegisterLine(registerNames[i], registers[i], registerNames[i+1], registers[i+1]))
|
||||
if nbRegisters % 2 == 1: print("{0:<15}{1:<20}".format(registerNames[nbRegisters - 1], "{0:08x}".format(registers[nbRegisters - 1])))
|
||||
|
||||
thumb = registers[16] & 0x20 != 0
|
||||
addr = registers[15] - codeDumpSize + (2 if thumb else 4)
|
||||
|
||||
print("\nCode dump:\n")
|
||||
|
||||
objdump_res = ""
|
||||
try:
|
||||
path = os.path.join(os.environ["DEVKITARM"], "bin", "arm-none-eabi-objdump")
|
||||
if os.name == "nt":
|
||||
path = ''.join((path[1], ':', path[2:])).replace('/', '\\')
|
||||
|
||||
objdump_res = subprocess.check_output((
|
||||
path, "-marm", "-b", "binary",
|
||||
"--adjust-vma="+hex(addr - codeOffset), "--start-address="+hex(addr),
|
||||
"--stop-address="+hex(addr + codeDumpSize), "-D", "-z", "-M",
|
||||
"reg-names-std" + (",force-thumb" if thumb else ""), args.filename
|
||||
)).decode("utf-8")
|
||||
objdump_res = '\n'.join(objdump_res[objdump_res.find('<.data+'):].split('\n')[1:])
|
||||
except: objdump_res = ""
|
||||
|
||||
print(objdump_res if objdump_res != "" else hexdump(addr, codeDump))
|
||||
|
||||
print("\nStack dump:\n")
|
||||
print(hexdump(registers[13], stackDump))
|
||||
16
linker.ld
16
linker.ld
@@ -1,11 +1,15 @@
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
|
||||
ENTRY(_start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x23F00000;
|
||||
.text.start : { *(.text.start) }
|
||||
.text : { *(.text) }
|
||||
.data : { *(.data) }
|
||||
.bss : { *(.bss COMMON) }
|
||||
.rodata : { *(.rodata) }
|
||||
. = 0x08006000;
|
||||
|
||||
.text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
|
||||
.rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
|
||||
.data : ALIGN(4) { *(.data*); . = ALIGN(4); }
|
||||
.bss : ALIGN(8) { __bss_start = .; *(.bss* COMMON); . = ALIGN(8); __bss_end = .; }
|
||||
|
||||
. = ALIGN(4);
|
||||
}
|
||||
|
||||
48
patches/emunand.s
Normal file
48
patches/emunand.s
Normal file
@@ -0,0 +1,48 @@
|
||||
; Code by Normmatt
|
||||
|
||||
.arm.little
|
||||
|
||||
.create "build/emunand.bin", 0
|
||||
.arm
|
||||
; Original code that still needs to be executed
|
||||
mov r4, r0
|
||||
mov r5, r1
|
||||
mov r7, r2
|
||||
mov r6, r3
|
||||
; End
|
||||
|
||||
; If we're already trying to access the SD, return
|
||||
ldr r2, [r0, #4]
|
||||
ldr r1, [sdmmc]
|
||||
cmp r2, r1
|
||||
beq out
|
||||
|
||||
str r1, [r0, #4] ; Set object to be SD
|
||||
ldr r2, [r0, #8] ; Get sector to read
|
||||
cmp r2, #0 ; For GW compatibility, see if we're trying to read the ncsd header (sector 0)
|
||||
|
||||
ldr r3, [nand_offset]
|
||||
add r2, r3 ; Add the offset to the NAND in the SD
|
||||
|
||||
ldreq r3, [ncsd_header_offset]
|
||||
addeq r2, r3 ; If we're reading the ncsd header, add the offset of that sector
|
||||
|
||||
str r2, [r0, #8] ; Store sector to read
|
||||
|
||||
out:
|
||||
; Restore registers.
|
||||
mov r1, r5
|
||||
mov r2, r7
|
||||
mov r3, r6
|
||||
|
||||
; Return 4 bytes behind where we got called,
|
||||
; due to the offset of this function being stored there
|
||||
mov r0, lr
|
||||
add r0, #4
|
||||
bx r0
|
||||
|
||||
.pool
|
||||
sdmmc: .ascii "SDMC"
|
||||
nand_offset: .ascii "NAND" ; For rednand this should be 1
|
||||
ncsd_header_offset: .ascii "NCSD" ; Depends on nand manufacturer + emunand type (GW/RED)
|
||||
.close
|
||||
73
patches/k11MainHook.s
Normal file
73
patches/k11MainHook.s
Normal file
@@ -0,0 +1,73 @@
|
||||
.arm.little
|
||||
|
||||
.create "build/k11MainHook.bin", 0
|
||||
.arm
|
||||
|
||||
bindSGI0:
|
||||
; hook __kernel_main to bind SGI0 for own purposes
|
||||
push {r0-r4, lr}
|
||||
sub sp, #16 ; 3 args passed through the stack + alignment
|
||||
ldr r0, [interruptManager]
|
||||
adr r1, interruptEvent
|
||||
mov r2, #0
|
||||
mrc p15, 0, r3, c0, c0, 5
|
||||
and r3, #3
|
||||
mov r4, #0
|
||||
str r4, [sp]
|
||||
str r4, [sp, #4]
|
||||
str r4, [sp, #8]
|
||||
|
||||
ldr r12, [InterruptManager_mapInterrupt]
|
||||
blx r12
|
||||
cmp r0, #0
|
||||
blt .
|
||||
|
||||
add sp, #16
|
||||
pop {r0-r4, pc}
|
||||
|
||||
executeCustomHandler:
|
||||
push {r4, lr}
|
||||
mrs r4, cpsr
|
||||
adr r0, customHandler
|
||||
bl convertVAToPA
|
||||
orr r0, #(1 << 31)
|
||||
ldr r12, [r0]
|
||||
|
||||
blx r12
|
||||
|
||||
mov r0, #0
|
||||
msr cpsr_cx, r4
|
||||
pop {r4, pc}
|
||||
|
||||
convertVAToPA:
|
||||
mov r1, #0x1000
|
||||
sub r1, #1
|
||||
and r2, r0, r1
|
||||
bic r0, r1
|
||||
mcr p15, 0, r0, c7, c8, 0 ; VA to PA translation with privileged read permission check
|
||||
mrc p15, 0, r0, c7, c4, 0 ; read PA register
|
||||
tst r0, #1 ; failure bit
|
||||
bic r0, r1
|
||||
addeq r0, r2
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
|
||||
; Result InterruptManager::mapInterrupt(InterruptManager *this, InterruptEvent *iEvent, u32 interruptID, u32 coreID, s32 priority, bool willBeMasked, bool isLevelHighActive);
|
||||
InterruptManager_mapInterrupt: .ascii "bind"
|
||||
|
||||
_vtable: .word executeCustomHandler
|
||||
interruptEvent: .word _vtable
|
||||
|
||||
parameters:
|
||||
customHandler: .ascii "hdlr"
|
||||
interruptManager: .word 0
|
||||
L2MMUTable: .word 0
|
||||
funcs: .word 0,0,0
|
||||
TTBCR: .word 0
|
||||
L1MMUTableAddrs: .word 0,0,0,0
|
||||
kernelVersion: .word 0
|
||||
CFWInfo: .word 0,0,0,0
|
||||
|
||||
.close
|
||||
36
patches/mmuHook.s
Normal file
36
patches/mmuHook.s
Normal file
@@ -0,0 +1,36 @@
|
||||
.arm.little
|
||||
|
||||
.create "build/mmuHook.bin", 0
|
||||
.arm
|
||||
; r2 = L1 table
|
||||
; Thanks @Dazzozo for giving me that idea
|
||||
; Maps physmem so that, if addr is in physmem(0, 0x30000000), it can be accessed uncached&rwx as addr|(1<<31)
|
||||
; Save the value of all registers
|
||||
|
||||
push {r0-r1, r3-r7}
|
||||
mov r0, #0
|
||||
mov r1, #0x30000000 ; end address
|
||||
ldr r3, =#0x40C02 ; supersection (rwx for all) of strongly ordered memory, shared
|
||||
loop:
|
||||
orr r4, r0, #0x80000000
|
||||
orr r5, r0, r3
|
||||
|
||||
mov r6, #0 ;
|
||||
loop2:
|
||||
add r7, r6, r4,lsr #20
|
||||
str r5, [r2, r7,lsl #2]
|
||||
add r6, #1
|
||||
cmp r6, #16
|
||||
blo loop2
|
||||
|
||||
add r0, #0x01000000
|
||||
cmp r0, r1
|
||||
blo loop
|
||||
pop {r0-r1, r3-r7}
|
||||
|
||||
mov r3, #0xe0000000 ; instruction that has been patched
|
||||
bx lr
|
||||
|
||||
|
||||
.pool
|
||||
.close
|
||||
209
patches/reboot.s
Normal file
209
patches/reboot.s
Normal file
@@ -0,0 +1,209 @@
|
||||
; Code originally from delebile and mid-kid
|
||||
|
||||
.arm.little
|
||||
|
||||
copy_launch_stub_stack_top equ 0x01FFB800
|
||||
copy_launch_stub_stack_bottom equ 0x01FFA800
|
||||
copy_launch_stub_addr equ 0x01FF9000
|
||||
|
||||
argv_addr equ (copy_launch_stub_stack_bottom - 0x100)
|
||||
fname_addr equ (copy_launch_stub_stack_bottom - 0x200)
|
||||
low_tid_addr equ (copy_launch_stub_stack_bottom - 0x300)
|
||||
|
||||
firm_addr equ 0x20001000
|
||||
firm_maxsize equ 0x07FFF000
|
||||
|
||||
.create "build/reboot.bin", 0
|
||||
.arm
|
||||
; Interesting registers and locations to keep in mind, set just before this code is ran:
|
||||
; - r1: FIRM path in exefs.
|
||||
; - r7 (or r8): pointer to file object
|
||||
; - *r7: vtable
|
||||
; - *(vtable + 0x28): fread function
|
||||
; - *(r7 + 8): file handle
|
||||
|
||||
sub r7, r0, #8
|
||||
mov r8, r1
|
||||
|
||||
pxi_wait_recv:
|
||||
ldr r2, =0x44846
|
||||
ldr r0, =0x10008000
|
||||
readPxiLoop1:
|
||||
ldrh r1, [r0, #4]
|
||||
lsls r1, #0x17
|
||||
bmi readPxiLoop1
|
||||
ldr r0, [r0, #0xC]
|
||||
cmp r0, r2
|
||||
bne pxi_wait_recv
|
||||
|
||||
; Open file
|
||||
add r0, r7, #8
|
||||
adr r1, fname
|
||||
mov r2, #1
|
||||
ldr r6, [fopen]
|
||||
orr r6, 1
|
||||
blx r6
|
||||
cmp r0, #0
|
||||
bne panic
|
||||
|
||||
; Read file
|
||||
mov r0, r7
|
||||
adr r1, bytes_read
|
||||
ldr r2, =firm_addr
|
||||
ldr r3, =firm_maxsize
|
||||
ldr r6, [r7]
|
||||
ldr r6, [r6, #0x28]
|
||||
blx r6
|
||||
|
||||
; Copy the low TID (in UTF-16) of the wanted firm
|
||||
ldr r0, =low_tid_addr
|
||||
add r1, r8, #0x1A
|
||||
mov r2, #0x10
|
||||
bl memcpy16
|
||||
|
||||
; Copy argv[0]
|
||||
ldr r0, =fname_addr
|
||||
adr r1, fname
|
||||
mov r2, #42
|
||||
bl memcpy16
|
||||
|
||||
ldr r0, =argv_addr
|
||||
ldr r1, =fname_addr
|
||||
ldr r2, =low_tid_addr
|
||||
stmia r0, {r1, r2}
|
||||
|
||||
; Set kernel state
|
||||
mov r0, #0
|
||||
mov r1, #0
|
||||
mov r2, #0
|
||||
mov r3, #0
|
||||
swi 0x7C
|
||||
|
||||
goto_reboot:
|
||||
; Jump to reboot code
|
||||
ldr r0, =(kernelcode_start - goto_reboot - 12)
|
||||
add r0, pc ; pc is two instructions ahead of the instruction being executed (12 = 2*4 + 4)
|
||||
swi 0x7B
|
||||
|
||||
die:
|
||||
b die
|
||||
|
||||
memcpy16:
|
||||
cmp r2, #0
|
||||
bxeq lr
|
||||
add r2, r0, r2
|
||||
copy_loop16:
|
||||
ldrh r3, [r1], #2
|
||||
strh r3, [r0], #2
|
||||
cmp r0, r2
|
||||
blo copy_loop16
|
||||
bx lr
|
||||
|
||||
panic:
|
||||
mov r1, r0 ; unused register
|
||||
mov r0, #0
|
||||
swi 0x3C ; svcBreak(USERBREAK_PANIC)
|
||||
b die
|
||||
|
||||
bytes_read: .word 0
|
||||
fopen: .ascii "OPEN"
|
||||
.pool
|
||||
|
||||
.area 82, 0
|
||||
fname: .ascii "FILE"
|
||||
.endarea
|
||||
|
||||
.align 4
|
||||
kernelcode_start:
|
||||
|
||||
mrs r0, cpsr ; disable interrupts
|
||||
orr r0, #0xC0
|
||||
msr cpsr, r0
|
||||
|
||||
ldr sp, =copy_launch_stub_stack_top
|
||||
|
||||
ldr r0, =copy_launch_stub_addr
|
||||
adr r1, copy_launch_stub
|
||||
mov r2, #(copy_launch_stub_end - copy_launch_stub)
|
||||
bl memcpy32
|
||||
|
||||
; Disable MPU
|
||||
ldr r0, =0x42078 ; alt vector select, enable itcm
|
||||
mcr p15, 0, r0, c1, c0, 0
|
||||
|
||||
bl flushCaches
|
||||
|
||||
ldr r0, =copy_launch_stub_addr
|
||||
bx r0
|
||||
|
||||
copy_launch_stub:
|
||||
|
||||
ldr r4, =firm_addr
|
||||
|
||||
mov r5, #0
|
||||
load_section_loop:
|
||||
; Such checks. Very ghetto. Wow.
|
||||
add r3, r4, #0x40
|
||||
add r3, r5,lsl #5
|
||||
add r3, r5,lsl #4
|
||||
ldmia r3, {r6-r8}
|
||||
cmp r8, #0
|
||||
movne r0, r7
|
||||
addne r1, r4, r6
|
||||
movne r2, r8
|
||||
blne memcpy32
|
||||
add r5, #1
|
||||
cmp r5, #3
|
||||
blo load_section_loop
|
||||
|
||||
mov r0, #2 ; argc
|
||||
ldr r1, =argv_addr ; argv
|
||||
ldr r2, =0xBABE ; magic word
|
||||
|
||||
mov r5, #0x20000000
|
||||
ldr r6, [r4, #0x08]
|
||||
str r6, [r5, #-4] ; store arm11 entrypoint
|
||||
|
||||
ldr lr, [r4, #0x0c]
|
||||
bx lr
|
||||
|
||||
memcpy32:
|
||||
add r2, r0, r2
|
||||
copy_loop32:
|
||||
ldr r3, [r1], #4
|
||||
str r3, [r0], #4
|
||||
cmp r0, r2
|
||||
blo copy_loop32
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
|
||||
copy_launch_stub_end:
|
||||
|
||||
flushCaches:
|
||||
|
||||
; Clean and flush data cache
|
||||
mov r1, #0 ; segment counter
|
||||
outer_loop:
|
||||
mov r0, #0 ; line counter
|
||||
|
||||
inner_loop:
|
||||
orr r2, r1, r0 ; generate segment and line address
|
||||
mcr p15, 0, r2, c7, c14, 2 ; clean and flush the line
|
||||
add r0, #0x20 ; increment to next line
|
||||
cmp r0, #0x400
|
||||
bne inner_loop
|
||||
|
||||
add r1, #0x40000000
|
||||
cmp r1, #0
|
||||
bne outer_loop
|
||||
|
||||
; Drain write buffer
|
||||
mcr p15, 0, r1, c7, c10, 4
|
||||
|
||||
; Flush instruction cache
|
||||
mcr p15, 0, r1, c7, c5, 0
|
||||
|
||||
bx lr
|
||||
|
||||
.close
|
||||
43
patches/svcConnectToPortInitHook.s
Normal file
43
patches/svcConnectToPortInitHook.s
Normal file
@@ -0,0 +1,43 @@
|
||||
.arm.little
|
||||
|
||||
.create "build/svcConnectToPortInitHook.bin", 0
|
||||
.arm
|
||||
push {r0-r4, lr}
|
||||
adr r0, jumpAddress
|
||||
bl convertVAToPA
|
||||
orr r4, r0, #(1 << 31)
|
||||
|
||||
loop:
|
||||
ldr r12, [r4]
|
||||
cmp r12, #0
|
||||
bne loop_end
|
||||
ldr r12, [SleepThread]
|
||||
ldr r0, =(10 * 1000 * 1000)
|
||||
mov r1, #0
|
||||
blx r12
|
||||
b loop
|
||||
|
||||
loop_end:
|
||||
pop {r0-r4, lr}
|
||||
bx r12
|
||||
|
||||
convertVAToPA:
|
||||
mov r1, #0x1000
|
||||
sub r1, #1
|
||||
and r2, r0, r1
|
||||
bic r0, r1
|
||||
mcr p15, 0, r0, c7, c8, 0 ; VA to PA translation with privileged read permission check
|
||||
mrc p15, 0, r0, c7, c4, 0 ; read PA register
|
||||
tst r0, #1 ; failure bit
|
||||
bic r0, r1
|
||||
addeq r0, r2
|
||||
movne r0, #0
|
||||
bx lr
|
||||
|
||||
.pool
|
||||
_base: .ascii "base"
|
||||
jumpAddressOrig: .ascii "orig"
|
||||
SleepThread: .ascii "SlpT"
|
||||
jumpAddress: .word 0
|
||||
|
||||
.close
|
||||
20
patches/svcCustomBackdoor.s
Normal file
20
patches/svcCustomBackdoor.s
Normal file
@@ -0,0 +1,20 @@
|
||||
.arm.little
|
||||
|
||||
.create "build/svcCustomBackdoor.bin", 0
|
||||
.arm
|
||||
|
||||
; Result svcCustomBackdoor(void *func, ... <up to 3 args>)
|
||||
svcCustomBackdoor:
|
||||
b skip_orig
|
||||
orig: .word 0
|
||||
skip_orig:
|
||||
push {r4, lr}
|
||||
mov r4, r0
|
||||
mov r0, r1
|
||||
mov r1, r2
|
||||
mov r2, r3
|
||||
blx r4
|
||||
pop {r4, pc}
|
||||
|
||||
.pool
|
||||
.close
|
||||
@@ -1,221 +0,0 @@
|
||||
.nds
|
||||
.create "reboot.bin", 0
|
||||
|
||||
byteswritten equ 0x2000E000
|
||||
externalFirm equ 0x2000A000
|
||||
kernelCode equ 0x080F0000
|
||||
buffer equ 0x24000000
|
||||
fileOpen equ 0x4E45504F ;dummy
|
||||
|
||||
.arm
|
||||
//Code jumps here right after the sprintf call
|
||||
process9Reboot:
|
||||
doPxi:
|
||||
ldr r4, =0x44846
|
||||
ldr r0, =0x10008000
|
||||
readPxiLoop1:
|
||||
ldrh r1, [r0,#4]
|
||||
.word 0xE1B01B81 //lsls r1, r1, #0x17
|
||||
bmi readPxiLoop1
|
||||
ldr r0, [r0,#0xC]
|
||||
cmp r0, r4
|
||||
bne doPxi
|
||||
|
||||
GetFirmPath:
|
||||
add r0, sp, #0x3A8-0x70+0x24
|
||||
ldr r1, [r0], #4
|
||||
ldr r2, =0x00300030
|
||||
cmp r1, r2
|
||||
ldreq r1, [r0], #4
|
||||
ldreq r2, =0x002F0032
|
||||
cmpeq r1, r2
|
||||
|
||||
OpenFirm:
|
||||
ldreq r1, =(FileName - OpenFirm - 12)
|
||||
addeq r1, pc
|
||||
addne r1, sp, #0x3A8-0x70
|
||||
ldr r0, =externalFirm
|
||||
moveq r2, #1
|
||||
movne r2, #0
|
||||
str r2, [r0]
|
||||
mov r2, #1
|
||||
add r0, r7, #8
|
||||
ldr r6, =fileOpen
|
||||
blx r6
|
||||
|
||||
SeekFirm:
|
||||
ldr r0, =externalFirm
|
||||
ldr r0, [r0]
|
||||
cmp r0, #1
|
||||
moveq r0, r7
|
||||
ldreq r1, =byteswritten
|
||||
ldreq r2, =buffer
|
||||
ldreq r3, =0x0
|
||||
ldreq r6, [sp,#0x3A8-0x198]
|
||||
ldreq r6, [r6,#0x28] //fread function stored here
|
||||
blxeq r6
|
||||
|
||||
ReadFirm:
|
||||
mov r0, r7
|
||||
ldr r1, =byteswritten
|
||||
ldr r2, =buffer
|
||||
ldr r3, =0x200000
|
||||
ldr r6, [sp,#0x3A8-0x198]
|
||||
ldr r6, [r6,#0x28] //fread function stored here
|
||||
blx r6
|
||||
|
||||
KernelSetState:
|
||||
mov r2, #0
|
||||
mov r3, r2
|
||||
mov r1, r2
|
||||
mov r0, r2
|
||||
.word 0xEF00007C //SVC 0x7C
|
||||
|
||||
GoToReboot:
|
||||
ldr r0, =(KernelCodeStart - GoToReboot - 12)
|
||||
add r0, pc
|
||||
ldr r1, =kernelCode
|
||||
ldr r2, =0x300
|
||||
bl Memcpy
|
||||
|
||||
ldr r0, =kernelCode
|
||||
.word 0xEF00007B //SVC 0x7B
|
||||
|
||||
InfiniteLoop:
|
||||
b InfiniteLoop
|
||||
|
||||
Memcpy:
|
||||
MOV R12, LR
|
||||
STMFD SP!, {R0-R4}
|
||||
ADD R2, R2, R0
|
||||
|
||||
memcpyLoop:
|
||||
LDR R3, [R0],#4
|
||||
STR R3, [R1],#4
|
||||
CMP R0, R2
|
||||
BLT memcpyLoop
|
||||
LDMFD SP!, {R0-R4}
|
||||
MOV LR, R12
|
||||
BX LR
|
||||
|
||||
FileName:
|
||||
.dcw "sdmc:/rei/patched_firmware_sys.bin"
|
||||
.word 0x0
|
||||
|
||||
.pool
|
||||
|
||||
// Kernel Code
|
||||
.align 4
|
||||
KernelCodeStart:
|
||||
memorySetting:
|
||||
MRC p15, 0, R0,c2,c0, 0
|
||||
MRC p15, 0, R12,c2,c0, 1
|
||||
MRC p15, 0, R1,c3,c0, 0
|
||||
MRC p15, 0, R2,c5,c0, 2
|
||||
MRC p15, 0, R3,c5,c0, 3
|
||||
LDR R4, =0x18000035
|
||||
BIC R2, R2, #0xF0000
|
||||
BIC R3, R3, #0xF0000
|
||||
ORR R0, R0, #0x10
|
||||
ORR R2, R2, #0x30000
|
||||
ORR R3, R3, #0x30000
|
||||
ORR R12, R12, #0x10
|
||||
ORR R1, R1, #0x10
|
||||
MCR p15, 0, R0,c2,c0, 0
|
||||
MCR p15, 0, R12,c2,c0, 1
|
||||
MCR p15, 0, R1,c3,c0, 0
|
||||
MCR p15, 0, R2,c5,c0, 2
|
||||
MCR p15, 0, R3,c5,c0, 3
|
||||
MCR p15, 0, R4,c6,c4, 0
|
||||
MRC p15, 0, R0,c2,c0, 0
|
||||
MRC p15, 0, R1,c2,c0, 1
|
||||
MRC p15, 0, R2,c3,c0, 0
|
||||
ORR R0, R0, #0x20
|
||||
ORR R1, R1, #0x20
|
||||
ORR R2, R2, #0x20
|
||||
MCR p15, 0, R0,c2,c0, 0
|
||||
MCR p15, 0, R1,c2,c0, 1
|
||||
MCR p15, 0, R2,c3,c0, 0
|
||||
|
||||
copyFirmPartitions:
|
||||
LDR R4, =buffer
|
||||
ADD R3, R4, #0x40
|
||||
LDR R0, [R3]
|
||||
ADD R0, R0, R4
|
||||
LDR R1, [R3,#4]
|
||||
LDR R2, [R3,#8]
|
||||
bl KernelMemcpy
|
||||
|
||||
ADD R3, R4, #0x70
|
||||
LDR R0, [R3]
|
||||
ADD R0, R0, R4
|
||||
LDR R1, [R3,#4]
|
||||
LDR R2, [R3,#8]
|
||||
bl KernelMemcpy
|
||||
|
||||
ADD R3, R4, #0xA0
|
||||
LDR R0, [R3]
|
||||
ADD R0, R0, R4
|
||||
LDR R1, [R3,#4]
|
||||
LDR R2, [R3,#8]
|
||||
bl KernelMemcpy
|
||||
|
||||
ADD R3, R4, #0xD0
|
||||
LDR R0, [R3]
|
||||
CMP R0, #0
|
||||
BEQ invalidateDataCache
|
||||
ADD R0, R0, R4
|
||||
LDR R1, [R3,#4]
|
||||
LDR R2, [R3,#8]
|
||||
bl KernelMemcpy
|
||||
|
||||
invalidateDataCache:
|
||||
MOV R2, #0
|
||||
MOV R1, R2
|
||||
loc_809460C:
|
||||
MOV R0, #0
|
||||
MOV R3, R2,LSL#30
|
||||
loc_8094614:
|
||||
ORR R12, R3, R0,LSL#5
|
||||
MCR p15, 0, R1,c7,c10, 4
|
||||
MCR p15, 0, R12,c7,c14, 2
|
||||
ADD R0, R0, #1
|
||||
CMP R0, #0x20
|
||||
BCC loc_8094614
|
||||
ADD R2, R2, #1
|
||||
CMP R2, #4
|
||||
BCC loc_809460C
|
||||
|
||||
jumpToEntrypoint:
|
||||
MCR p15, 0, R1,c7,c10, 4
|
||||
LDR R0, =0x42078
|
||||
MCR p15, 0, R0,c1,c0, 0
|
||||
MCR p15, 0, R1,c7,c5, 0
|
||||
MCR p15, 0, R1,c7,c6, 0
|
||||
MCR p15, 0, R1,c7,c10, 4
|
||||
LDR R4, =buffer
|
||||
MOV R1, #0x1FFFFFFC
|
||||
LDR R2, [R4,#8]
|
||||
STR R2, [R1]
|
||||
LDR R0, [R4,#0xC]
|
||||
BX R0
|
||||
.pool
|
||||
|
||||
KernelMemcpy:
|
||||
MOV R12, LR
|
||||
STMFD SP!, {R0-R4}
|
||||
ADD R2, R2, R0
|
||||
|
||||
kmemcpyLoop:
|
||||
LDR R3, [R0],#4
|
||||
STR R3, [R1],#4
|
||||
CMP R0, R2
|
||||
BLT kmemcpyLoop
|
||||
LDMFD SP!, {R0-R4}
|
||||
MOV LR, R12
|
||||
BX LR
|
||||
.pool
|
||||
|
||||
KernelCodeEnd:
|
||||
|
||||
.close
|
||||
167
source/3dsheaders.h
Normal file
167
source/3dsheaders.h
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Adapted from 3DBrew and https://github.com/mid-kid/CakesForeveryWan/blob/master/source/headers.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u32 address;
|
||||
u32 phyRegionSize;
|
||||
u32 size;
|
||||
} CodeSetInfo;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u32 saveDataSize[2];
|
||||
u32 jumpID[2];
|
||||
u8 reserved[0x30];
|
||||
} SystemInfo;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
char appTitle[8];
|
||||
u8 reserved1[5];
|
||||
u8 flag;
|
||||
u8 remasterVersion[2];
|
||||
CodeSetInfo textCodeSet;
|
||||
u32 stackSize;
|
||||
CodeSetInfo roCodeSet;
|
||||
u8 reserved2[4];
|
||||
CodeSetInfo dataCodeSet;
|
||||
u32 bssSize;
|
||||
char depends[0x180];
|
||||
SystemInfo systemInfo;
|
||||
} SystemControlInfo;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
SystemControlInfo systemControlInfo;
|
||||
u8 aci[0x200];
|
||||
u8 accessDescSig[0x100];
|
||||
u8 ncchPubKey[0x100];
|
||||
u8 aciLim[0x200];
|
||||
} ExHeader;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u8 sig[0x100]; //RSA-2048 signature of the NCCH header, using SHA-256
|
||||
char magic[4]; //NCCH
|
||||
u32 contentSize; //Media unit
|
||||
u8 partitionId[8];
|
||||
u8 makerCode[2];
|
||||
u16 version;
|
||||
u8 reserved1[4];
|
||||
u8 programID[8];
|
||||
u8 reserved2[0x10];
|
||||
u8 logoHash[0x20]; //Logo Region SHA-256 hash
|
||||
char productCode[0x10];
|
||||
u8 exHeaderHash[0x20]; //Extended header SHA-256 hash
|
||||
u32 exHeaderSize; //Extended header size
|
||||
u32 reserved3;
|
||||
u8 flags[8];
|
||||
u32 plainOffset; //Media unit
|
||||
u32 plainSize; //Media unit
|
||||
u32 logoOffset; //Media unit
|
||||
u32 logoSize; //Media unit
|
||||
u32 exeFsOffset; //Media unit
|
||||
u32 exeFsSize; //Media unit
|
||||
u32 exeFsHashSize; //Media unit
|
||||
u32 reserved4;
|
||||
u32 romFsOffset; //Media unit
|
||||
u32 romFsSize; //Media unit
|
||||
u32 romFsHashSize; //Media unit
|
||||
u32 reserved5;
|
||||
u8 exeFsHash[0x20]; //ExeFS superblock SHA-256 hash
|
||||
u8 romFsHash[0x20]; //RomFS superblock SHA-256 hash
|
||||
} Ncch;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
Ncch ncch;
|
||||
ExHeader exHeader;
|
||||
} Cxi;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
char sigIssuer[0x40];
|
||||
u8 eccPubKey[0x3C];
|
||||
u8 version;
|
||||
u8 caCrlVersion;
|
||||
u8 signerCrlVersion;
|
||||
u8 titleKey[0x10];
|
||||
u8 reserved1;
|
||||
u8 ticketId[8];
|
||||
u8 consoleId[4];
|
||||
u8 titleId[8];
|
||||
u8 reserved2[2];
|
||||
u16 ticketTitleVersion;
|
||||
u8 reserved3[8];
|
||||
u8 licenseType;
|
||||
u8 ticketCommonKeyYIndex; //Ticket common keyY index, usually 0x1 for retail system titles.
|
||||
u8 reserved4[0x2A];
|
||||
u8 unk[4]; //eShop Account ID?
|
||||
u8 reserved5;
|
||||
u8 audit;
|
||||
u8 reserved6[0x42];
|
||||
u8 limits[0x40];
|
||||
u8 contentIndex[0xAC];
|
||||
} Ticket;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u32 offset;
|
||||
u8 *address;
|
||||
u32 size;
|
||||
u32 procType;
|
||||
u8 hash[0x20];
|
||||
} FirmSection;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
char magic[4];
|
||||
u32 reserved1;
|
||||
u8 *arm11Entry;
|
||||
u8 *arm9Entry;
|
||||
u8 reserved2[0x30];
|
||||
FirmSection section[4];
|
||||
} Firm;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u8 keyX[0x10];
|
||||
u8 keyY[0x10];
|
||||
u8 ctr[0x10];
|
||||
char size[8];
|
||||
u8 reserved[8];
|
||||
u8 ctlBlock[0x10];
|
||||
char magic[4];
|
||||
u8 reserved2[0xC];
|
||||
u8 slot0x16keyX[0x10];
|
||||
} Arm9Bin;
|
||||
51
source/buttons.h
Normal file
51
source/buttons.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
|
||||
|
||||
#define BUTTON_R1 (1 << 8)
|
||||
#define BUTTON_L1 (1 << 9)
|
||||
#define BUTTON_A (1 << 0)
|
||||
#define BUTTON_B (1 << 1)
|
||||
#define BUTTON_X (1 << 10)
|
||||
#define BUTTON_Y (1 << 11)
|
||||
#define BUTTON_SELECT (1 << 2)
|
||||
#define BUTTON_START (1 << 3)
|
||||
#define BUTTON_RIGHT (1 << 4)
|
||||
#define BUTTON_LEFT (1 << 5)
|
||||
#define BUTTON_UP (1 << 6)
|
||||
#define BUTTON_DOWN (1 << 7)
|
||||
|
||||
#define DPAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
|
||||
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
||||
#define SINGLE_PAYLOAD_BUTTONS (DPAD_BUTTONS | BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT)
|
||||
#define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START)
|
||||
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START | BUTTON_SELECT)
|
||||
43
source/cache.h
Normal file
43
source/cache.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/***
|
||||
The following functions flush the data cache, then waits for all memory transfers to be finished.
|
||||
The data cache and/or the instruction cache MUST be flushed before doing one of the following:
|
||||
- rebooting
|
||||
- powering down
|
||||
- setting the ARM11 entrypoint to execute a function
|
||||
- jumping to a payload
|
||||
***/
|
||||
|
||||
void flushEntireDCache(void); //actually: "clean and flush"
|
||||
void flushDCacheRange(void *startAddress, u32 size);
|
||||
void flushEntireICache(void);
|
||||
void flushICacheRange(void *startAddress, u32 size);
|
||||
93
source/cache.s
Normal file
93
source/cache.s
Normal file
@@ -0,0 +1,93 @@
|
||||
@ This file is part of Luma3DS
|
||||
@ Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
@ * Requiring preservation of specified reasonable legal notices or
|
||||
@ author attributions in that material or in the Appropriate Legal
|
||||
@ Notices displayed by works containing it.
|
||||
@ * Prohibiting misrepresentation of the origin of that material,
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
|
||||
.text
|
||||
.arm
|
||||
.align 4
|
||||
|
||||
.global flushEntireDCache
|
||||
.type flushEntireDCache, %function
|
||||
flushEntireDCache:
|
||||
@ Adapted from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html,
|
||||
@ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
|
||||
@ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
|
||||
|
||||
@ Implemented in bootROM at address 0xffff0830
|
||||
mov r1, #0 @ segment counter
|
||||
outer_loop:
|
||||
mov r0, #0 @ line counter
|
||||
|
||||
inner_loop:
|
||||
orr r2, r1, r0 @ generate segment and line address
|
||||
mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
|
||||
add r0, #0x20 @ increment to next line
|
||||
cmp r0, #0x400
|
||||
bne inner_loop
|
||||
|
||||
add r1, #0x40000000
|
||||
cmp r1, #0
|
||||
bne outer_loop
|
||||
|
||||
mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
|
||||
bx lr
|
||||
|
||||
.global flushDCacheRange
|
||||
.type flushDCacheRange, %function
|
||||
flushDCacheRange:
|
||||
@ Implemented in bootROM at address 0xffff08a0
|
||||
add r1, r0, r1 @ end address
|
||||
bic r0, #0x1f @ align source address to cache line size (32 bytes)
|
||||
|
||||
flush_dcache_range_loop:
|
||||
mcr p15, 0, r0, c7, c14, 1 @ clean and flush the line corresponding to the address r0 is holding
|
||||
add r0, #0x20
|
||||
cmp r0, r1
|
||||
blo flush_dcache_range_loop
|
||||
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
|
||||
bx lr
|
||||
|
||||
.global flushEntireICache
|
||||
.type flushEntireICache, %function
|
||||
flushEntireICache:
|
||||
@ Implemented in bootROM at address 0xffff0ab4
|
||||
mov r0, #0
|
||||
mcr p15, 0, r0, c7, c5, 0
|
||||
bx lr
|
||||
|
||||
.global flushICacheRange
|
||||
.type flushICacheRange, %function
|
||||
flushICacheRange:
|
||||
@ Implemented in bootROM at address 0xffff0ac0
|
||||
add r1, r0, r1 @ end address
|
||||
bic r0, #0x1f @ align source address to cache line size (32 bytes)
|
||||
|
||||
flush_icache_range_loop:
|
||||
mcr p15, 0, r0, c7, c5, 1 @ flush the line corresponding to the address r0 is holding
|
||||
add r0, #0x20
|
||||
cmp r0, r1
|
||||
blo flush_icache_range_loop
|
||||
|
||||
bx lr
|
||||
392
source/config.c
Normal file
392
source/config.c
Normal file
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "memory.h"
|
||||
#include "fs.h"
|
||||
#include "utils.h"
|
||||
#include "screen.h"
|
||||
#include "draw.h"
|
||||
#include "buttons.h"
|
||||
#include "pin.h"
|
||||
|
||||
CfgData configData;
|
||||
ConfigurationStatus needConfig;
|
||||
static u32 oldConfig;
|
||||
|
||||
bool readConfig(void)
|
||||
{
|
||||
bool ret;
|
||||
|
||||
if(fileRead(&configData, CONFIG_FILE, sizeof(CfgData)) != sizeof(CfgData) ||
|
||||
memcmp(configData.magic, "CONF", 4) != 0 ||
|
||||
configData.formatVersionMajor != CONFIG_VERSIONMAJOR ||
|
||||
configData.formatVersionMinor != CONFIG_VERSIONMINOR)
|
||||
{
|
||||
configData.config = 0;
|
||||
|
||||
ret = false;
|
||||
}
|
||||
else ret = true;
|
||||
|
||||
oldConfig = configData.config;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void writeConfig(bool isPayloadLaunch)
|
||||
{
|
||||
if(isPayloadLaunch) configData.config = (configData.config & 0xFFFFFF80) | (oldConfig & 0x7F);
|
||||
|
||||
/* If the configuration is different from previously, overwrite it.
|
||||
Just the no-forcing flag being set is not enough */
|
||||
if(needConfig != CREATE_CONFIGURATION && (configData.config & 0xFFFFFFBF) == oldConfig) return;
|
||||
|
||||
if(needConfig == CREATE_CONFIGURATION)
|
||||
{
|
||||
memcpy(configData.magic, "CONF", 4);
|
||||
configData.formatVersionMajor = CONFIG_VERSIONMAJOR;
|
||||
configData.formatVersionMinor = CONFIG_VERSIONMINOR;
|
||||
}
|
||||
|
||||
if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData)))
|
||||
error("Error writing the configuration file");
|
||||
}
|
||||
|
||||
void configMenu(bool oldPinStatus, u32 oldPinMode)
|
||||
{
|
||||
const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )",
|
||||
"Screen brightness: 4( ) 3( ) 2( ) 1( )",
|
||||
"Splash: Off( ) Before( ) After( ) payloads",
|
||||
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
|
||||
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )",
|
||||
};
|
||||
|
||||
const char *singleOptionsText[] = { "( ) Autoboot EmuNAND",
|
||||
"( ) Use EmuNAND FIRM if booting with R",
|
||||
"( ) Enable loading external FIRMs and modules",
|
||||
"( ) Enable game patching",
|
||||
"( ) Show NAND or user string in System Settings",
|
||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||
"( ) Patch ARM9 access",
|
||||
"( ) Set developer UNITINFO",
|
||||
};
|
||||
|
||||
const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
|
||||
"It will be booted when no\n"
|
||||
"directional pad buttons are pressed.",
|
||||
|
||||
"Select the screen brightness.",
|
||||
|
||||
"Enable splash screen support.\n\n"
|
||||
"\t* 'Before payloads' displays it\n"
|
||||
"before booting payloads\n"
|
||||
"(intended for splashes that display\n"
|
||||
"button hints).\n\n"
|
||||
"\t* 'After payloads' displays it\n"
|
||||
"afterwards.",
|
||||
|
||||
"Activate a PIN lock.\n\n"
|
||||
"The PIN will be asked each time\n"
|
||||
"Luma3DS boots.\n\n"
|
||||
"4, 6 or 8 digits can be selected.\n\n"
|
||||
"The ABXY buttons and the directional\n"
|
||||
"pad buttons can be used as keys.\n\n"
|
||||
"A message can also be displayed\n"
|
||||
"(refer to the wiki for instructions).",
|
||||
|
||||
"Select the New 3DS CPU mode.\n\n"
|
||||
"This won't apply to\n"
|
||||
"New 3DS exclusive/enhanced games.\n\n"
|
||||
"'Clock+L2' can cause issues with some\n"
|
||||
"games.",
|
||||
|
||||
"If enabled, an EmuNAND\n"
|
||||
"will be launched on boot.\n\n"
|
||||
"Otherwise, SysNAND will.\n\n"
|
||||
"Hold L on boot to switch NAND.\n\n"
|
||||
"To use a different EmuNAND from the\n"
|
||||
"default, hold a directional pad button\n"
|
||||
"(Up/Right/Down/Left equal EmuNANDs\n"
|
||||
"1/2/3/4).",
|
||||
|
||||
"If enabled, when holding R on boot\n"
|
||||
"SysNAND will be booted with an\n"
|
||||
"EmuNAND FIRM.\n\n"
|
||||
"Otherwise, an EmuNAND will be booted\n"
|
||||
"with the SysNAND FIRM.\n\n"
|
||||
"To use a different EmuNAND from the\n"
|
||||
"default, hold a directional pad button\n"
|
||||
"(Up/Right/Down/Left equal EmuNANDs\n"
|
||||
"1/2/3/4), also add A if you have\n"
|
||||
"a matching payload.",
|
||||
|
||||
"Enable loading external FIRMs and\n"
|
||||
"system modules.\n\n"
|
||||
"This isn't needed in most cases.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
|
||||
"Enable overriding the region and\n"
|
||||
"language configuration and the usage\n"
|
||||
"of patched code binaries,\n"
|
||||
"IPS code patches and LayeredFS\n"
|
||||
"for specific games.\n\n"
|
||||
"Also makes certain DLCs\n"
|
||||
"for out-of-region games work.\n\n"
|
||||
"Enabling this requires the\n"
|
||||
"archive patch to be applied.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
|
||||
"Enable showing the current NAND/FIRM:\n\n"
|
||||
"\t* Sys = SysNAND\n"
|
||||
"\t* Emu = EmuNAND 1\n"
|
||||
"\t* EmuX = EmuNAND X\n"
|
||||
"\t* SysE = SysNAND with EmuNAND 1 FIRM\n"
|
||||
"\t* SyEX = SysNAND with EmuNAND X FIRM\n"
|
||||
"\t* EmuS = EmuNAND 1 with SysNAND FIRM\n"
|
||||
"\t* EmXS = EmuNAND X with SysNAND FIRM\n\n"
|
||||
"or a user-defined custom string in\n"
|
||||
"System Settings.\n\n"
|
||||
"Refer to the wiki for instructions.",
|
||||
|
||||
"Enable showing the GBA boot screen\n"
|
||||
"when booting GBA games.",
|
||||
|
||||
"Disable ARM9 exheader access checks.\n\n"
|
||||
"Only select this if you know what you\n"
|
||||
"are doing!",
|
||||
|
||||
"Make the console be always detected\n"
|
||||
"as a development unit, and conversely.\n"
|
||||
"(which breaks online features, amiibo\n"
|
||||
"and retail CIAs, but allows installing\n"
|
||||
"and booting some developer software).\n\n"
|
||||
"Only select this if you know what you\n"
|
||||
"are doing!",
|
||||
};
|
||||
|
||||
struct multiOption {
|
||||
u32 posXs[4];
|
||||
u32 posY;
|
||||
u32 enabled;
|
||||
bool visible;
|
||||
} multiOptions[] = {
|
||||
{ .posXs = {19, 24, 29, 34}, .visible = isSdMode },
|
||||
{ .posXs = {21, 26, 31, 36}, .visible = true },
|
||||
{ .posXs = {12, 22, 31, 0}, .visible = true },
|
||||
{ .posXs = {14, 19, 24, 29}, .visible = true },
|
||||
{ .posXs = {17, 26, 32, 44}, .visible = ISN3DS },
|
||||
};
|
||||
|
||||
struct singleOption {
|
||||
u32 posY;
|
||||
bool enabled;
|
||||
bool visible;
|
||||
} singleOptions[] = {
|
||||
{ .visible = isSdMode },
|
||||
{ .visible = isSdMode },
|
||||
{ .visible = true },
|
||||
{ .visible = true },
|
||||
{ .visible = true },
|
||||
{ .visible = true },
|
||||
{ .visible = true },
|
||||
{ .visible = true }
|
||||
};
|
||||
|
||||
//Calculate the amount of the various kinds of options and pre-select the first single one
|
||||
u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption),
|
||||
singleOptionsAmount = sizeof(singleOptions) / sizeof(struct singleOption),
|
||||
totalIndexes = multiOptionsAmount + singleOptionsAmount - 1,
|
||||
selectedOption,
|
||||
singleSelected;
|
||||
bool isMultiOption = false;
|
||||
|
||||
//Parse the existing options
|
||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||
multiOptions[i].enabled = MULTICONFIG(i);
|
||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||
singleOptions[i].enabled = CONFIG(i);
|
||||
|
||||
initScreens();
|
||||
|
||||
drawString(true, 10, 10, COLOR_TITLE, CONFIG_TITLE);
|
||||
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press A to select, START to save");
|
||||
|
||||
//Character to display a selected option
|
||||
char selected = 'x';
|
||||
|
||||
u32 endPos = 10 + 2 * SPACING_Y;
|
||||
|
||||
//Display all the multiple choice options in white
|
||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||
{
|
||||
if(!multiOptions[i].visible) continue;
|
||||
|
||||
multiOptions[i].posY = endPos + SPACING_Y;
|
||||
endPos = drawString(true, 10, multiOptions[i].posY, COLOR_WHITE, multiOptionsText[i]);
|
||||
drawCharacter(true, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE, selected);
|
||||
}
|
||||
|
||||
endPos += SPACING_Y / 2;
|
||||
|
||||
//Display all the normal options in white except for the first one
|
||||
for(u32 i = 0, color = COLOR_RED; i < singleOptionsAmount; i++)
|
||||
{
|
||||
if(!singleOptions[i].visible) continue;
|
||||
|
||||
singleOptions[i].posY = endPos + SPACING_Y;
|
||||
endPos = drawString(true, 10, singleOptions[i].posY, color, singleOptionsText[i]);
|
||||
if(singleOptions[i].enabled) drawCharacter(true, 10 + SPACING_X, singleOptions[i].posY, color, selected);
|
||||
|
||||
if(color == COLOR_RED)
|
||||
{
|
||||
singleSelected = i;
|
||||
selectedOption = i + multiOptionsAmount;
|
||||
color = COLOR_WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
drawString(false, 10, 10, COLOR_WHITE, optionsDescription[selectedOption]);
|
||||
|
||||
//Boring configuration menu
|
||||
while(true)
|
||||
{
|
||||
u32 pressed;
|
||||
do
|
||||
{
|
||||
pressed = waitInput(true);
|
||||
}
|
||||
while(!(pressed & MENU_BUTTONS));
|
||||
|
||||
if(pressed == BUTTON_START) break;
|
||||
|
||||
if(pressed != BUTTON_A)
|
||||
{
|
||||
//Remember the previously selected option
|
||||
u32 oldSelectedOption = selectedOption;
|
||||
|
||||
while(true)
|
||||
{
|
||||
switch(pressed)
|
||||
{
|
||||
case BUTTON_UP:
|
||||
selectedOption = !selectedOption ? totalIndexes : selectedOption - 1;
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
selectedOption = selectedOption == totalIndexes ? 0 : selectedOption + 1;
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
pressed = BUTTON_DOWN;
|
||||
selectedOption = 0;
|
||||
break;
|
||||
case BUTTON_RIGHT:
|
||||
pressed = BUTTON_UP;
|
||||
selectedOption = totalIndexes;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(selectedOption < multiOptionsAmount)
|
||||
{
|
||||
if(!multiOptions[selectedOption].visible) continue;
|
||||
|
||||
isMultiOption = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
singleSelected = selectedOption - multiOptionsAmount;
|
||||
|
||||
if(!singleOptions[singleSelected].visible) continue;
|
||||
|
||||
isMultiOption = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(selectedOption == oldSelectedOption) continue;
|
||||
|
||||
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
|
||||
if(oldSelectedOption < multiOptionsAmount)
|
||||
{
|
||||
drawString(true, 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE, multiOptionsText[oldSelectedOption]);
|
||||
drawCharacter(true, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE, selected);
|
||||
}
|
||||
else
|
||||
{
|
||||
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
|
||||
drawString(true, 10, singleOptions[singleOldSelected].posY, COLOR_WHITE, singleOptionsText[singleOldSelected]);
|
||||
if(singleOptions[singleOldSelected].enabled) drawCharacter(true, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE, selected);
|
||||
}
|
||||
|
||||
if(isMultiOption) drawString(true, 10, multiOptions[selectedOption].posY, COLOR_RED, multiOptionsText[selectedOption]);
|
||||
else drawString(true, 10, singleOptions[singleSelected].posY, COLOR_RED, singleOptionsText[singleSelected]);
|
||||
|
||||
drawString(false, 10, 10, COLOR_BLACK, optionsDescription[oldSelectedOption]);
|
||||
drawString(false, 10, 10, COLOR_WHITE, optionsDescription[selectedOption]);
|
||||
}
|
||||
else
|
||||
{
|
||||
//The selected option's status changed, print the 'x's accordingly
|
||||
if(isMultiOption)
|
||||
{
|
||||
u32 oldEnabled = multiOptions[selectedOption].enabled;
|
||||
drawCharacter(true, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK, selected);
|
||||
multiOptions[selectedOption].enabled = (oldEnabled == 3 || !multiOptions[selectedOption].posXs[oldEnabled + 1]) ? 0 : oldEnabled + 1;
|
||||
|
||||
if(selectedOption == BRIGHTNESS) updateBrightness(multiOptions[BRIGHTNESS].enabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool oldEnabled = singleOptions[singleSelected].enabled;
|
||||
singleOptions[singleSelected].enabled = !oldEnabled;
|
||||
if(oldEnabled) drawCharacter(true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_BLACK, selected);
|
||||
}
|
||||
}
|
||||
|
||||
//In any case, if the current option is enabled (or a multiple choice option is selected) we must display a red 'x'
|
||||
if(isMultiOption) drawCharacter(true, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED, selected);
|
||||
else if(singleOptions[singleSelected].enabled) drawCharacter(true, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED, selected);
|
||||
}
|
||||
|
||||
//Preserve the last-used boot options (first 9 bits)
|
||||
configData.config &= 0x7F;
|
||||
|
||||
//Parse and write the new configuration
|
||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||
configData.config |= multiOptions[i].enabled << (i * 2 + 7);
|
||||
for(u32 i = 0; i < singleOptionsAmount; i++)
|
||||
configData.config |= (singleOptions[i].enabled ? 1 : 0) << (i + 17);
|
||||
|
||||
u32 newPinMode = MULTICONFIG(PIN);
|
||||
|
||||
if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode);
|
||||
else if(oldPinStatus) fileDelete(PIN_FILE);
|
||||
|
||||
while(HID_PAD & PIN_BUTTONS);
|
||||
wait(2000ULL);
|
||||
}
|
||||
73
source/config.h
Normal file
73
source/config.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define CONFIG(a) (((configData.config >> (a + 17)) & 1) != 0)
|
||||
#define MULTICONFIG(a) ((configData.config >> (a * 2 + 7)) & 3)
|
||||
#define BOOTCONFIG(a, b) ((configData.config >> a) & b)
|
||||
|
||||
#define CONFIG_FILE "config.bin"
|
||||
#define CONFIG_VERSIONMAJOR 1
|
||||
#define CONFIG_VERSIONMINOR 12
|
||||
|
||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||
#define BOOTCFG_NOFORCEFLAG BOOTCONFIG(6, 1)
|
||||
|
||||
enum multiOptions
|
||||
{
|
||||
DEFAULTEMU = 0,
|
||||
BRIGHTNESS,
|
||||
SPLASH,
|
||||
PIN,
|
||||
NEWCPU
|
||||
};
|
||||
|
||||
enum singleOptions
|
||||
{
|
||||
AUTOBOOTEMU = 0,
|
||||
USEEMUFIRM,
|
||||
LOADEXTFIRMSANDMODULES,
|
||||
PATCHGAMES,
|
||||
PATCHVERSTRING,
|
||||
SHOWGBABOOT,
|
||||
PATCHACCESS,
|
||||
PATCHUNITINFO
|
||||
};
|
||||
|
||||
typedef enum ConfigurationStatus
|
||||
{
|
||||
DONT_CONFIGURE = 0,
|
||||
MODIFY_CONFIGURATION,
|
||||
CREATE_CONFIGURATION
|
||||
} ConfigurationStatus;
|
||||
|
||||
bool readConfig(void);
|
||||
void writeConfig(bool isPayloadLaunch);
|
||||
void configMenu(bool oldPinStatus, u32 oldPinMode);
|
||||
969
source/crypto.c
969
source/crypto.c
File diff suppressed because it is too large
Load Diff
220
source/crypto.h
220
source/crypto.h
@@ -1,138 +1,126 @@
|
||||
// From http://github.com/b1l1s/ctr
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef __CRYPTO_H
|
||||
#define __CRYPTO_H
|
||||
/*
|
||||
* Crypto libs from http://github.com/b1l1s/ctr
|
||||
* kernel9Loader code originally adapted from https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233
|
||||
* decryptNusFirm code adapted from https://github.com/mid-kid/CakesForeveryWan/blob/master/source/firm.c
|
||||
* ctrNandWrite logic adapted from https://github.com/d0k3/GodMode9/blob/master/source/nand/nand.c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "types.h"
|
||||
|
||||
#define FIRM_TYPE_ARM9 0
|
||||
#define FIRM_TYPE_ARM11 1
|
||||
|
||||
#define MEDIA_UNITS 0x200
|
||||
|
||||
#define NCCH_MAGIC (0x4843434E)
|
||||
#define NCSD_MAGIC (0x4453434E)
|
||||
#define FIRM_MAGIC (0x4D524946)
|
||||
#define ARM9BIN_MAGIC (0x47704770)
|
||||
|
||||
/**************************AES****************************/
|
||||
#define REG_AESCNT ((volatile u32*)0x10009000)
|
||||
#define REG_AESBLKCNT ((volatile u32*)0x10009004)
|
||||
#define REG_AESWRFIFO ((volatile u32*)0x10009008)
|
||||
#define REG_AESRDFIFO ((volatile u32*)0x1000900C)
|
||||
#define REG_AESKEYSEL ((volatile u8 *)0x10009010)
|
||||
#define REG_AESKEYCNT ((volatile u8 *)0x10009011)
|
||||
#define REG_AESCTR ((volatile u32*)0x10009020)
|
||||
#define REG_AESCNT ((vu32 *)0x10009000)
|
||||
#define REG_AESBLKCNT ((vu32 *)0x10009004)
|
||||
#define REG_AESWRFIFO ((vu32 *)0x10009008)
|
||||
#define REG_AESRDFIFO ((vu32 *)0x1000900C)
|
||||
#define REG_AESKEYSEL ((vu8 *)0x10009010)
|
||||
#define REG_AESKEYCNT ((vu8 *)0x10009011)
|
||||
#define REG_AESCTR ((vu32 *)0x10009020)
|
||||
|
||||
#define REG_AESKEYFIFO ((volatile u32*)0x10009100)
|
||||
#define REG_AESKEYXFIFO ((volatile u32*)0x10009104)
|
||||
#define REG_AESKEYYFIFO ((volatile u32*)0x10009108)
|
||||
#define REG_AESKEYFIFO ((vu32 *)0x10009100)
|
||||
#define REG_AESKEYXFIFO ((vu32 *)0x10009104)
|
||||
#define REG_AESKEYYFIFO ((vu32 *)0x10009108)
|
||||
|
||||
#define AES_CCM_DECRYPT_MODE (0u << 27)
|
||||
#define AES_CCM_ENCRYPT_MODE (1u << 27)
|
||||
#define AES_CTR_MODE (2u << 27)
|
||||
#define AES_CTR_MODE (2u << 27)
|
||||
#define AES_CBC_DECRYPT_MODE (4u << 27)
|
||||
#define AES_CBC_ENCRYPT_MODE (5u << 27)
|
||||
#define AES_ECB_DECRYPT_MODE (6u << 27)
|
||||
#define AES_ECB_ENCRYPT_MODE (7u << 27)
|
||||
#define AES_ALL_MODES (7u << 27)
|
||||
#define REGs_AESTWLKEYS (*((vu32 (*)[4][3][4])0x10009040))
|
||||
|
||||
#define AES_CNT_START 0x80000000
|
||||
#define AES_CNT_INPUT_ORDER 0x02000000
|
||||
#define AES_CNT_OUTPUT_ORDER 0x01000000
|
||||
#define AES_CNT_INPUT_ENDIAN 0x00800000
|
||||
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
|
||||
#define AES_CNT_FLUSH_READ 0x00000800
|
||||
#define AES_CNT_FLUSH_WRITE 0x00000400
|
||||
#define AES_CCM_DECRYPT_MODE (0u << 27)
|
||||
#define AES_CCM_ENCRYPT_MODE (1u << 27)
|
||||
#define AES_CTR_MODE (2u << 27)
|
||||
#define AES_CTR_MODE (2u << 27)
|
||||
#define AES_CBC_DECRYPT_MODE (4u << 27)
|
||||
#define AES_CBC_ENCRYPT_MODE (5u << 27)
|
||||
#define AES_ECB_DECRYPT_MODE (6u << 27)
|
||||
#define AES_ECB_ENCRYPT_MODE (7u << 27)
|
||||
#define AES_ALL_MODES (7u << 27)
|
||||
|
||||
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
|
||||
#define AES_INPUT_LE 0
|
||||
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
|
||||
#define AES_INPUT_REVERSED 0
|
||||
#define AES_CNT_START 0x80000000
|
||||
#define AES_CNT_INPUT_ORDER 0x02000000
|
||||
#define AES_CNT_OUTPUT_ORDER 0x01000000
|
||||
#define AES_CNT_INPUT_ENDIAN 0x00800000
|
||||
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
|
||||
#define AES_CNT_FLUSH_READ 0x00000800
|
||||
#define AES_CNT_FLUSH_WRITE 0x00000400
|
||||
|
||||
#define AES_TEMP_KEYSLOT 0x11
|
||||
#define AES_INPUT_BE (AES_CNT_INPUT_ENDIAN)
|
||||
#define AES_INPUT_LE 0
|
||||
#define AES_INPUT_NORMAL (AES_CNT_INPUT_ORDER)
|
||||
#define AES_INPUT_REVERSED 0
|
||||
#define AES_INPUT_TWLNORMAL 0
|
||||
#define AES_INPUT_TWLREVERSED (AES_CNT_INPUT_ORDER)
|
||||
|
||||
#define AES_BLOCK_SIZE 0x10
|
||||
#define AES_BLOCK_SIZE 0x10
|
||||
|
||||
#define AES_KEYCNT_WRITE (1 << 0x7)
|
||||
#define AES_KEYNORMAL 0
|
||||
#define AES_KEYX 1
|
||||
#define AES_KEYY 2
|
||||
#define AES_KEYCNT_WRITE (1 << 0x7)
|
||||
#define AES_KEYNORMAL 0
|
||||
#define AES_KEYX 1
|
||||
#define AES_KEYY 2
|
||||
|
||||
/**************************SHA****************************/
|
||||
#define REG_SHA_CNT ((volatile u32*)0x1000A000)
|
||||
#define REG_SHA_BLKCNT ((volatile u32*)0x1000A004)
|
||||
#define REG_SHA_HASH ((volatile u32*)0x1000A040)
|
||||
#define REG_SHA_INFIFO ((volatile u32*)0x1000A080)
|
||||
#define REG_SHA_CNT ((vu32 *)0x1000A000)
|
||||
#define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
|
||||
#define REG_SHA_HASH ((vu32 *)0x1000A040)
|
||||
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
|
||||
|
||||
#define SHA_CNT_STATE 0x00000003
|
||||
#define SHA_CNT_UNK2 0x00000004
|
||||
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
|
||||
#define SHA_CNT_MODE 0x00000030
|
||||
#define SHA_CNT_ENABLE 0x00010000
|
||||
#define SHA_CNT_ACTIVE 0x00020000
|
||||
#define SHA_CNT_STATE 0x00000003
|
||||
#define SHA_CNT_UNK2 0x00000004
|
||||
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
|
||||
#define SHA_CNT_MODE 0x00000030
|
||||
#define SHA_CNT_ENABLE 0x00010000
|
||||
#define SHA_CNT_ACTIVE 0x00020000
|
||||
|
||||
#define SHA_HASH_READY 0x00000000
|
||||
#define SHA_NORMAL_ROUND 0x00000001
|
||||
#define SHA_FINAL_ROUND 0x00000002
|
||||
#define SHA_HASH_READY 0x00000000
|
||||
#define SHA_NORMAL_ROUND 0x00000001
|
||||
#define SHA_FINAL_ROUND 0x00000002
|
||||
|
||||
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
|
||||
#define SHA_OUTPUT_LE 0
|
||||
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
|
||||
#define SHA_OUTPUT_LE 0
|
||||
|
||||
#define SHA_256_MODE 0
|
||||
#define SHA_224_MODE 0x00000010
|
||||
#define SHA_1_MODE 0x00000020
|
||||
#define SHA_256_MODE 0
|
||||
#define SHA_224_MODE 0x00000010
|
||||
#define SHA_1_MODE 0x00000020
|
||||
|
||||
#define SHA_256_HASH_SIZE (256 / 8)
|
||||
#define SHA_224_HASH_SIZE (224 / 8)
|
||||
#define SHA_1_HASH_SIZE (160 / 8)
|
||||
#define SHA_256_HASH_SIZE (256 / 8)
|
||||
#define SHA_224_HASH_SIZE (224 / 8)
|
||||
#define SHA_1_HASH_SIZE (160 / 8)
|
||||
|
||||
/**************************RSA****************************/
|
||||
#define REG_RSA_CNT ((volatile u32*)0x1000B000)
|
||||
#define REG_RSA_SLOT0 ((volatile u32*)0x1000B100)
|
||||
#define REG_RSA_SLOT1 ((volatile u32*)0x1000B110)
|
||||
#define REG_RSA_SLOT2 ((volatile u32*)0x1000B120)
|
||||
#define REG_RSA_SLOT3 ((volatile u32*)0x1000B130)
|
||||
#define REG_RSA_EXPFIFO ((volatile u32*)0x1000B200)
|
||||
#define REG_RSA_MOD_END ((volatile u32*)0x1000B500)
|
||||
#define REG_RSA_TXT_END ((volatile u32*)0x1000B900)
|
||||
extern u32 emuOffset,
|
||||
emuHeader;
|
||||
extern FirmwareSource firmSource;
|
||||
|
||||
#define RSA_CNT_START 0x00000001
|
||||
#define RSA_CNT_KEYSLOTS 0x000000F0
|
||||
#define RSA_CNT_IO_ENDIAN 0x00000100
|
||||
#define RSA_CNT_IO_ORDER 0x00000200
|
||||
void sha(void *res, const void *src, u32 size, u32 mode);
|
||||
|
||||
#define RSA_SLOTCNT_KEY_SET 0x00000001
|
||||
#define RSA_SLOTCNT_WPROTECT 0x00000002 // Write protect
|
||||
|
||||
#define RSA_IO_BE RSA_CNT_IO_ENDIAN
|
||||
#define RSA_IO_LE 0
|
||||
#define RSA_IO_NORMAL RSA_CNT_IO_ORDER
|
||||
#define RSA_IO_REVERSED 0
|
||||
|
||||
#define RSA_TEMP_KEYSLOT 0
|
||||
|
||||
#define RSA_1024_MODE 0x20
|
||||
#define RSA_2048_MODE 0x40
|
||||
|
||||
//Crypto Libs
|
||||
void aes_setkey(u8 keyslot, const void* key, u32 keyType, u32 mode);
|
||||
void aes_use_keyslot(u8 keyslot);
|
||||
void aes(void* dst, const void* src, u32 blockCount, void* iv, u32 mode, u32 ivMode);
|
||||
void aes_setiv(const void* iv, u32 mode);
|
||||
void aes_advctr(void* ctr, u32 val, u32 mode);
|
||||
void aes_change_ctrmode(void* ctr, u32 fromMode, u32 toMode);
|
||||
void aes_batch(void* dst, const void* src, u32 blockCount);
|
||||
void sha(void* res, const void* src, u32 size, u32 mode);
|
||||
void rsa_setkey(u32 keyslot, const void* mod, const void* exp, u32 mode);
|
||||
void rsa_use_keyslot(u32 keyslot);
|
||||
int rsa_verify(const void* data, u32 size, const void* sig, u32 mode);
|
||||
|
||||
//NAND/FIRM stuff
|
||||
void nandFirm0(u8 *outbuf, const u32 size, u8 console);
|
||||
void decArm9Bin(void *armHdr, u8 mode);
|
||||
void setKeyXs(void *armHdr);
|
||||
|
||||
#endif /*__CRYPTO_H*/
|
||||
int ctrNandInit(void);
|
||||
int ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
|
||||
int ctrNandWrite(u32 sector, u32 sectorCount, const u8 *inbuf);
|
||||
bool decryptExeFs(Cxi *cxi);
|
||||
bool decryptNusFirm(const Ticket *ticket, Cxi *cxi, u32 ncchSize);
|
||||
void setupKeyslots(void);
|
||||
void kernel9Loader(Arm9Bin *arm9Section);
|
||||
void computePinHash(u8 *outbuf, const u8 *inbuf);
|
||||
|
||||
142
source/draw.c
142
source/draw.c
@@ -1,44 +1,126 @@
|
||||
/*
|
||||
* draw.c
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Code to print to the screen by mid-kid @CakesFW
|
||||
* https://github.com/mid-kid/CakesForeveryWan
|
||||
*/
|
||||
|
||||
#include "draw.h"
|
||||
#include "strings.h"
|
||||
#include "screen.h"
|
||||
#include "utils.h"
|
||||
#include "fs.h"
|
||||
#include "memory.h"
|
||||
#include "types.h"
|
||||
#include "fmt.h"
|
||||
#include "font.h"
|
||||
|
||||
static struct fb *fb = (struct fb *)0x23FFFE00;
|
||||
bool loadSplash(void)
|
||||
{
|
||||
const char *topSplashFile = "splash.bin",
|
||||
*bottomSplashFile = "splashbottom.bin";
|
||||
|
||||
void shutdownLCD(void){
|
||||
bool isTopSplashValid = getFileSize(topSplashFile) == SCREEN_TOP_FBSIZE,
|
||||
isBottomSplashValid = getFileSize(bottomSplashFile) == SCREEN_BOTTOM_FBSIZE;
|
||||
|
||||
vu32 *arm11 = (vu32*)0x1FFFFFF8;
|
||||
//Don't delay boot nor init the screens if no splash images or invalid splash images are on the SD
|
||||
if(!isTopSplashValid && !isBottomSplashValid) return false;
|
||||
|
||||
//Clear ARM11 entry offset
|
||||
*arm11 = 0;
|
||||
initScreens();
|
||||
clearScreens(true);
|
||||
|
||||
//Shutdown LCDs
|
||||
*(vu32*)0x10202A44 = 0;
|
||||
*(vu32*)0x10202244 = 0;
|
||||
*(vu32*)0x10202014 = 0;
|
||||
|
||||
//Wait for the ARM11 entrypoint to be set
|
||||
while (!*arm11);
|
||||
//Jump to it
|
||||
((void (*)())*arm11)();
|
||||
if(isTopSplashValid) isTopSplashValid = fileRead(fbs[1].top_left, topSplashFile, SCREEN_TOP_FBSIZE) == SCREEN_TOP_FBSIZE;
|
||||
if(isBottomSplashValid) isBottomSplashValid = fileRead(fbs[1].bottom, bottomSplashFile, SCREEN_BOTTOM_FBSIZE) == SCREEN_BOTTOM_FBSIZE;
|
||||
|
||||
if(!isTopSplashValid && !isBottomSplashValid) return false;
|
||||
|
||||
swapFramebuffers(true);
|
||||
wait(3000ULL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clearScreen(void){
|
||||
memset(fb->top_left, 0, 0x46500);
|
||||
memset(fb->top_right, 0, 0x46500);
|
||||
memset(fb->bottom, 0, 0x38400);
|
||||
void drawCharacter(bool isTopScreen, u32 posX, u32 posY, u32 color, char character)
|
||||
{
|
||||
u8 *select = isTopScreen ? fbs[0].top_left : fbs[0].bottom;
|
||||
|
||||
for(u32 y = 0; y < 8; y++)
|
||||
{
|
||||
char charPos = font[character * 8 + y];
|
||||
|
||||
for(u32 x = 0; x < 8; x++)
|
||||
if(((charPos >> (7 - x)) & 1) == 1)
|
||||
{
|
||||
u32 screenPos = (posX * SCREEN_HEIGHT * 3 + (SCREEN_HEIGHT - y - posY - 1) * 3) + x * 3 * SCREEN_HEIGHT;
|
||||
|
||||
select[screenPos] = color >> 16;
|
||||
select[screenPos + 1] = color >> 8;
|
||||
select[screenPos + 2] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loadSplash(void){
|
||||
//Check if it's a no-screen-init A9LH boot via PDN_GPU_CNT
|
||||
if (*((u8*)0x10141200) == 0x1) return;
|
||||
clearScreen();
|
||||
if(fileRead(fb->top_left, "/rei/splash.bin", 0x46500) != 0) return;
|
||||
u64 i = 0xFFFFFF; while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
|
||||
}
|
||||
u32 drawString(bool isTopScreen, u32 posX, u32 posY, u32 color, const char *string)
|
||||
{
|
||||
for(u32 i = 0, line_i = 0; i < strlen(string); i++)
|
||||
switch(string[i])
|
||||
{
|
||||
case '\n':
|
||||
posY += SPACING_Y;
|
||||
line_i = 0;
|
||||
break;
|
||||
|
||||
case '\t':
|
||||
line_i += 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
//Make sure we never get out of the screen
|
||||
if(line_i >= ((isTopScreen ? SCREEN_TOP_WIDTH : SCREEN_BOTTOM_WIDTH) - posX) / SPACING_X)
|
||||
{
|
||||
posY += SPACING_Y;
|
||||
line_i = 1; //Little offset so we know the same string continues
|
||||
if(string[i] == ' ') break; //Spaces at the start look weird
|
||||
}
|
||||
|
||||
drawCharacter(isTopScreen, posX + line_i * SPACING_X, posY, color, string[i]);
|
||||
|
||||
line_i++;
|
||||
break;
|
||||
}
|
||||
|
||||
return posY;
|
||||
}
|
||||
|
||||
u32 drawFormattedString(bool isTopScreen, u32 posX, u32 posY, u32 color, const char *fmt, ...)
|
||||
{
|
||||
char buf[DRAW_MAX_FORMATTED_STRING_SIZE + 1];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
return drawString(isTopScreen, posX, posY, color, buf);
|
||||
}
|
||||
|
||||
@@ -1,16 +1,50 @@
|
||||
/*
|
||||
* draw.h
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Code to print to the screen by mid-kid @CakesFW
|
||||
* https://github.com/mid-kid/CakesForeveryWan/
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
struct fb {
|
||||
u8 *top_left;
|
||||
u8 *top_right;
|
||||
u8 *bottom;
|
||||
};
|
||||
#define SPACING_Y 10
|
||||
#define SPACING_X 8
|
||||
|
||||
void loadSplash(void);
|
||||
void shutdownLCD(void);
|
||||
#define COLOR_TITLE 0xFF9900
|
||||
#define COLOR_WHITE 0xFFFFFF
|
||||
#define COLOR_RED 0x0000FF
|
||||
#define COLOR_BLACK 0x000000
|
||||
#define COLOR_YELLOW 0x00FFFF
|
||||
|
||||
#define DRAW_MAX_FORMATTED_STRING_SIZE 512
|
||||
|
||||
bool loadSplash(void);
|
||||
void drawCharacter(bool isTopScreen, u32 posX, u32 posY, u32 color, char character);
|
||||
u32 drawString(bool isTopScreen, u32 posX, u32 posY, u32 color, const char *string);
|
||||
u32 drawFormattedString(bool isTopScreen, u32 posX, u32 posY, u32 color, const char *fmt, ...);
|
||||
|
||||
216
source/emunand.c
216
source/emunand.c
@@ -1,56 +1,200 @@
|
||||
/*
|
||||
* emunand.c
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Code for locating the SDMMC struct by Normmatt
|
||||
*/
|
||||
|
||||
#include "emunand.h"
|
||||
#include "memory.h"
|
||||
#include "fatfs/ff.h"
|
||||
#include "fatfs/sdmmc/sdmmc.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
static u8 *temp = (u8*)0x24300000;
|
||||
u32 emuOffset,
|
||||
emuHeader;
|
||||
|
||||
void getEmunandSect(u32 *off, u32 *head){
|
||||
u32 nandSize = getMMCDevice(0)->total_size;
|
||||
if (sdmmc_sdcard_readsectors(nandSize, 1, temp) == 0) {
|
||||
if (*(u32*)(temp + 0x100) == NCSD_MAGIC) {
|
||||
*off = 0;
|
||||
*head = nandSize;
|
||||
}
|
||||
void locateEmuNand(FirmwareSource *nandType)
|
||||
{
|
||||
static u8 __attribute__((aligned(4))) temp[0x200];
|
||||
static u32 nandSize = 0,
|
||||
fatStart;
|
||||
|
||||
if(!nandSize)
|
||||
{
|
||||
nandSize = getMMCDevice(0)->total_size;
|
||||
sdmmc_sdcard_readsectors(0, 1, temp);
|
||||
fatStart = *(u32 *)(temp + 0x1C6); //First sector of the FAT partition
|
||||
}
|
||||
|
||||
for(u32 i = 0; i < 3; i++)
|
||||
{
|
||||
static const u32 roundedMinsizes[] = {0x1D8000, 0x26E000};
|
||||
|
||||
u32 nandOffset;
|
||||
switch(i)
|
||||
{
|
||||
case 1:
|
||||
nandOffset = ROUND_TO_4MB(nandSize + 1); //"Default" layout
|
||||
break;
|
||||
case 2:
|
||||
nandOffset = roundedMinsizes[ISN3DS ? 1 : 0]; //"Minsize" layout
|
||||
break;
|
||||
case 0:
|
||||
nandOffset = *nandType == FIRMWARE_EMUNAND ? 0 : (nandSize > 0x200000 ? 0x400000 : 0x200000); //"Legacy" layout
|
||||
break;
|
||||
}
|
||||
|
||||
if(*nandType != FIRMWARE_EMUNAND) nandOffset *= ((u32)*nandType - 1);
|
||||
|
||||
if(fatStart >= nandOffset + roundedMinsizes[ISN3DS ? 1 : 0])
|
||||
{
|
||||
//Check for RedNAND
|
||||
if(!sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) && memcmp(temp + 0x100, "NCSD", 4) == 0)
|
||||
{
|
||||
emuOffset = nandOffset + 1;
|
||||
emuHeader = nandOffset + 1;
|
||||
return;
|
||||
}
|
||||
|
||||
//Check for Gateway EmuNAND
|
||||
else if(i != 2 && !sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) && memcmp(temp + 0x100, "NCSD", 4) == 0)
|
||||
{
|
||||
emuOffset = nandOffset;
|
||||
emuHeader = nandOffset + nandSize;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if(*nandType == FIRMWARE_EMUNAND) break;
|
||||
}
|
||||
|
||||
//Fallback to the first EmuNAND if there's no second/third/fourth one, or to SysNAND if there isn't any
|
||||
if(*nandType != FIRMWARE_EMUNAND)
|
||||
{
|
||||
*nandType = FIRMWARE_EMUNAND;
|
||||
locateEmuNand(nandType);
|
||||
}
|
||||
else *nandType = FIRMWARE_SYSNAND;
|
||||
}
|
||||
|
||||
void getSDMMC(void *pos, u32 *off, u32 size){
|
||||
static inline bool getFreeK9Space(u8 *pos, u32 size, u8 **freeK9Space)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
|
||||
|
||||
//Looking for the last free space before Process9
|
||||
*freeK9Space = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(*freeK9Space == NULL) return false;
|
||||
|
||||
*freeK9Space += 0x455;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline u32 getSdmmc(u8 *pos, u32 size, u32 *sdmmc)
|
||||
{
|
||||
//Look for struct code
|
||||
unsigned char pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||
*off = (u32)memsearch(pos, pattern, size, 4) - 1;
|
||||
|
||||
//Get DCD values
|
||||
unsigned char buf[4];
|
||||
int p;
|
||||
u32 addr = 0,
|
||||
additive = 0;
|
||||
memcpy((void*)buf, (void*)(*off+0x0A), 4);
|
||||
for (p = 0; p < 4; p++) addr |= ((u32) buf[p]) << (8 * p);
|
||||
memcpy((void*)buf, (void*)(*off+0x0E), 4);
|
||||
for (p = 0; p < 4; p++) additive |= ((u32) buf[p]) << (8 * p);
|
||||
|
||||
//Return result
|
||||
*off = addr + additive;
|
||||
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
|
||||
|
||||
const u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
*sdmmc = *(u32 *)(off + 9) + *(u32 *)(off + 0xD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff){
|
||||
static inline u32 patchNandRw(u8 *pos, u32 size, u32 branchOffset)
|
||||
{
|
||||
//Look for read/write code
|
||||
unsigned char pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
|
||||
|
||||
*writeOff = (u32)memsearch(pos, pattern, size, 4) - 6;
|
||||
*readOff = (u32)memsearch((void *)(*writeOff - 0x1000), pattern, 0x1000, 4) - 6;
|
||||
u16 *readOffset = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(readOffset == NULL) return 1;
|
||||
|
||||
readOffset -= 3;
|
||||
|
||||
u16 *writeOffset = (u16 *)memsearch((u8 *)(readOffset + 5), pattern, 0x100, sizeof(pattern));
|
||||
|
||||
if(writeOffset == NULL) return 1;
|
||||
|
||||
writeOffset -= 3;
|
||||
*readOffset = *writeOffset = 0x4C00;
|
||||
readOffset[1] = writeOffset[1] = 0x47A0;
|
||||
((u32 *)writeOffset)[1] = ((u32 *)readOffset)[1] = branchOffset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void getMPU(void *pos, u32 *off, u32 size){
|
||||
static inline u32 patchMpu(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for MPU pattern
|
||||
unsigned char pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
|
||||
|
||||
*off = (u32)memsearch(pos, pattern, size, 4);
|
||||
}
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[1] = 0x0036;
|
||||
off[0xC] = off[0x12] = 0x0603;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address)
|
||||
{
|
||||
u8 *freeK9Space;
|
||||
|
||||
if(!getFreeK9Space(arm9Section, kernel9Size, &freeK9Space)) return 1;
|
||||
|
||||
u32 ret = 0;
|
||||
|
||||
//Copy EmuNAND code
|
||||
memcpy(freeK9Space, emunand_bin, emunand_bin_size);
|
||||
|
||||
//Add the data of the found EmuNAND
|
||||
u32 *posOffset = (u32 *)memsearch(freeK9Space, "NAND", emunand_bin_size, 4),
|
||||
*posHeader = (u32 *)memsearch(freeK9Space, "NCSD", emunand_bin_size, 4);
|
||||
*posOffset = emuOffset;
|
||||
*posHeader = emuHeader;
|
||||
|
||||
//Find and add the SDMMC struct
|
||||
u32 *posSdmmc = (u32 *)memsearch(freeK9Space, "SDMC", emunand_bin_size, 4);
|
||||
u32 sdmmc;
|
||||
ret += getSdmmc(process9Offset, process9Size, &sdmmc);
|
||||
if(!ret) *posSdmmc = sdmmc;
|
||||
|
||||
//Add EmuNAND hooks
|
||||
u32 branchOffset = (u32)(freeK9Space - arm9Section + kernel9Address);
|
||||
ret += patchNandRw(process9Offset, process9Size, branchOffset);
|
||||
|
||||
//Set MPU
|
||||
ret += patchMpu(arm9Section, kernel9Size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,38 @@
|
||||
/*
|
||||
* emunand.h
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef EMU_INC
|
||||
#define EMU_INC
|
||||
/*
|
||||
* Code for locating the SDMMC struct by Normmatt
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define NCSD_MAGIC (0x4453434E)
|
||||
#define ROUND_TO_4MB(a) (((a) + 0x2000 - 1) & (~(0x2000 - 1)))
|
||||
|
||||
void getEmunandSect(u32 *off, u32 *head);
|
||||
void getSDMMC(void *pos, u32 *off, u32 size);
|
||||
void getEmuRW(void *pos, u32 size, u32 *readOff, u32 *writeOff);
|
||||
void getMPU(void *pos, u32 *off, u32 size);
|
||||
|
||||
#endif
|
||||
void locateEmuNand(FirmwareSource *nandType);
|
||||
u32 patchEmuNand(u8 *arm9Section, u32 kernel9Size, u8 *process9Offset, u32 process9Size, u8 *kernel9Address);
|
||||
|
||||
157
source/exceptions.c
Normal file
157
source/exceptions.c
Normal file
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "exceptions.h"
|
||||
#include "fs.h"
|
||||
#include "strings.h"
|
||||
#include "memory.h"
|
||||
#include "screen.h"
|
||||
#include "draw.h"
|
||||
#include "utils.h"
|
||||
#include "fmt.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
void installArm9Handlers(void)
|
||||
{
|
||||
memcpy((void *)0x01FF8000, arm9_exceptions_bin + 32, arm9_exceptions_bin_size - 32);
|
||||
|
||||
/* IRQHandler is at 0x08000000, but we won't handle it for some reasons
|
||||
svcHandler is at 0x08000010, but we won't handle svc either */
|
||||
|
||||
const u32 offsets[] = {0x08, 0x18, 0x20, 0x28};
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
*(vu32 *)(0x08000000 + offsets[i]) = 0xE51FF004;
|
||||
*(vu32 *)(0x08000000 + offsets[i] + 4) = *((u32 *)arm9_exceptions_bin + 1 + i);
|
||||
}
|
||||
}
|
||||
|
||||
void detectAndProcessExceptionDumps(void)
|
||||
{
|
||||
volatile ExceptionDumpHeader *dumpHeader = (volatile ExceptionDumpHeader *)0x25000000;
|
||||
|
||||
if(dumpHeader->magic[0] != 0xDEADC0DE || dumpHeader->magic[1] != 0xDEADCAFE || (dumpHeader->processor != 9 && dumpHeader->processor != 11)) return;
|
||||
|
||||
const vu32 *regs = (vu32 *)((vu8 *)dumpHeader + sizeof(ExceptionDumpHeader));
|
||||
const vu8 *stackDump = (vu8 *)regs + dumpHeader->registerDumpSize + dumpHeader->codeDumpSize;
|
||||
const vu8 *additionalData = stackDump + dumpHeader->stackDumpSize;
|
||||
|
||||
const char *handledExceptionNames[] = {
|
||||
"FIQ", "undefined instruction", "prefetch abort", "data abort"
|
||||
};
|
||||
|
||||
const char *specialExceptions[] = {
|
||||
"kernel panic", "svcBreak"
|
||||
};
|
||||
|
||||
const char *registerNames[] = {
|
||||
"R0", "R1", "R2", "R3", "R4", "R5", "R6", "R7", "R8", "R9", "R10", "R11", "R12",
|
||||
"SP", "LR", "PC", "CPSR", "FPEXC"
|
||||
};
|
||||
|
||||
initScreens();
|
||||
|
||||
drawString(true, 10, 10, COLOR_RED, "An exception occurred");
|
||||
u32 posY;
|
||||
if(dumpHeader->processor == 11) posY = drawFormattedString(true, 10, 30, COLOR_WHITE, "Processor: ARM11 (core %u)", dumpHeader->core);
|
||||
else posY = drawString(true, 10, 30, COLOR_WHITE, "Processor: ARM9");
|
||||
|
||||
if(dumpHeader->type == 2)
|
||||
{
|
||||
if((regs[16] & 0x20) == 0 && dumpHeader->codeDumpSize >= 4)
|
||||
{
|
||||
u32 instr = *(vu32 *)(stackDump - 4);
|
||||
if(instr == 0xE12FFF7E)
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s (%s)", handledExceptionNames[dumpHeader->type], specialExceptions[0]);
|
||||
else if(instr == 0xEF00003C)
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s (%s)", handledExceptionNames[dumpHeader->type], specialExceptions[1]);
|
||||
else
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||
}
|
||||
else if((regs[16] & 0x20) != 0 && dumpHeader->codeDumpSize >= 2)
|
||||
{
|
||||
u16 instr = *(vu16 *)(stackDump - 2);
|
||||
if(instr == 0xDF3C)
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s (%s)", handledExceptionNames[dumpHeader->type], specialExceptions[0]);
|
||||
else
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||
}
|
||||
}
|
||||
else
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Exception type: %s", handledExceptionNames[dumpHeader->type]);
|
||||
|
||||
if(dumpHeader->processor == 11 && dumpHeader->additionalDataSize != 0)
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE,
|
||||
"Current process: %.8s (%016llX)", (const char *)additionalData, *(vu64 *)(additionalData + 8));
|
||||
posY += SPACING_Y;
|
||||
|
||||
for(u32 i = 0; i < 17; i += 2)
|
||||
{
|
||||
posY = drawFormattedString(true, 10, posY + SPACING_Y, COLOR_WHITE, "%-7s%08X", registerNames[i], regs[i]);
|
||||
|
||||
if(i != 16 || dumpHeader->processor != 9)
|
||||
posY = drawFormattedString(true, 10 + 22 * SPACING_X, posY, COLOR_WHITE, "%-7s%08X", registerNames[i + 1], regs[i + 1]);
|
||||
}
|
||||
|
||||
posY += SPACING_Y;
|
||||
|
||||
u32 mode = regs[16] & 0xF;
|
||||
if(dumpHeader->type == 3 && (mode == 7 || mode == 11))
|
||||
posY = drawString(true, 10, posY + SPACING_Y, COLOR_YELLOW, "Incorrect dump: failed to dump code and/or stack") + SPACING_Y;
|
||||
|
||||
u32 posYBottom = drawString(false, 10, 10, COLOR_WHITE, "Stack dump:") + SPACING_Y;
|
||||
|
||||
for(u32 line = 0; line < 19 && stackDump < additionalData; line++)
|
||||
{
|
||||
posYBottom = drawFormattedString(false, 10, posYBottom + SPACING_Y, COLOR_WHITE, "%08X:", regs[13] + 8 * line);
|
||||
|
||||
for(u32 i = 0; i < 8 && stackDump < additionalData; i++, stackDump++)
|
||||
drawFormattedString(false, 10 + 10 * SPACING_X + 3 * i * SPACING_X, posYBottom, COLOR_WHITE, "%02X", *stackDump);
|
||||
}
|
||||
|
||||
char folderPath[12],
|
||||
path[36],
|
||||
fileName[24];
|
||||
|
||||
sprintf(folderPath, "dumps/arm%u", dumpHeader->processor);
|
||||
findDumpFile(folderPath, fileName);
|
||||
sprintf(path, "%s/%s", folderPath, fileName);
|
||||
|
||||
if(fileWrite((void *)dumpHeader, path, dumpHeader->totalSize))
|
||||
{
|
||||
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "You can find a dump in the following file:");
|
||||
posY = drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, path) + SPACING_Y;
|
||||
}
|
||||
else posY = drawString(true, 10, posY + SPACING_Y, COLOR_RED, "Error writing the dump file");
|
||||
|
||||
drawString(true, 10, posY + SPACING_Y, COLOR_WHITE, "Press any button to shutdown");
|
||||
|
||||
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
||||
|
||||
waitInput(false);
|
||||
mcuPowerOff();
|
||||
}
|
||||
36
source/exceptions.h
Normal file
36
source/exceptions.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define MAKE_BRANCH(src,dst) (0xEA000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||
#define MAKE_BRANCH_LINK(src,dst) (0xEB000000 | ((u32)((((u8 *)(dst) - (u8 *)(src)) >> 2) - 2) & 0xFFFFFF))
|
||||
|
||||
void installArm9Handlers(void);
|
||||
u32 installArm11Handlers(u32 *exceptionsPage, u32 stackAddress, u32 codeSetOffset, u32 *dAbtHandler, u32 dAbtHandlerMemAddress);
|
||||
void detectAndProcessExceptionDumps(void);
|
||||
@@ -1,180 +1,288 @@
|
||||
----------------------------------------------------------------------------
|
||||
Revision history of FatFs module
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
R0.00 (February 26, 2006)
|
||||
Prototype.
|
||||
|
||||
|
||||
R0.01 (April 29, 2006)
|
||||
First stable version.
|
||||
|
||||
|
||||
R0.02 (June 01, 2006)
|
||||
Added FAT12 support.
|
||||
Removed unbuffered mode.
|
||||
Fixed a problem on small (<32M) partition.
|
||||
|
||||
|
||||
R0.02a (June 10, 2006)
|
||||
Added a configuration option (_FS_MINIMUM).
|
||||
|
||||
|
||||
R0.03 (September 22, 2006)
|
||||
Added f_rename().
|
||||
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
||||
|
||||
|
||||
R0.03a (December 11, 2006)
|
||||
Improved cluster scan algorithm to write files fast.
|
||||
Fixed f_mkdir() creates incorrect directory on FAT32.
|
||||
|
||||
|
||||
R0.04 (February 04, 2007)
|
||||
Added f_mkfs().
|
||||
Supported multiple drive system.
|
||||
Changed some interfaces for multiple drive system.
|
||||
Changed f_mountdrv() to f_mount().
|
||||
|
||||
|
||||
R0.04a (April 01, 2007)
|
||||
Supported multiple partitions on a physical drive.
|
||||
Added a capability of extending file size to f_lseek().
|
||||
Added minimization level 3.
|
||||
Fixed an endian sensitive code in f_mkfs().
|
||||
|
||||
|
||||
R0.04b (May 05, 2007)
|
||||
Added a configuration option _USE_NTFLAG.
|
||||
Added FSINFO support.
|
||||
Fixed DBCS name can result FR_INVALID_NAME.
|
||||
Fixed short seek (<= csize) collapses the file object.
|
||||
|
||||
|
||||
R0.05 (August 25, 2007)
|
||||
Changed arguments of f_read(), f_write() and f_mkfs().
|
||||
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
||||
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
||||
|
||||
|
||||
R0.05a (February 03, 2008)
|
||||
Added f_truncate() and f_utime().
|
||||
Fixed off by one error at FAT sub-type determination.
|
||||
Fixed btr in f_read() can be mistruncated.
|
||||
Fixed cached sector is not flushed when create and close without write.
|
||||
|
||||
|
||||
R0.06 (April 01, 2008)
|
||||
Added fputc(), fputs(), fprintf() and fgets().
|
||||
Improved performance of f_lseek() on moving to the same or following cluster.
|
||||
|
||||
|
||||
R0.07 (April 01, 2009)
|
||||
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
||||
Added long file name feature. (_USE_LFN)
|
||||
Added multiple code page feature. (_CODE_PAGE)
|
||||
Added re-entrancy for multitask operation. (_FS_REENTRANT)
|
||||
Added auto cluster size selection to f_mkfs().
|
||||
Added rewind option to f_readdir().
|
||||
Changed result code of critical errors.
|
||||
Renamed string functions to avoid name collision.
|
||||
|
||||
|
||||
R0.07a (April 14, 2009)
|
||||
Septemberarated out OS dependent code on reentrant cfg.
|
||||
Added multiple sector size feature.
|
||||
|
||||
|
||||
R0.07c (June 21, 2009)
|
||||
Fixed f_unlink() can return FR_OK on error.
|
||||
Fixed wrong cache control in f_lseek().
|
||||
Added relative path feature.
|
||||
Added f_chdir() and f_chdrive().
|
||||
Added proper case conversion to extended character.
|
||||
|
||||
|
||||
R0.07e (November 03, 2009)
|
||||
Septemberarated out configuration options from ff.h to ffconf.h.
|
||||
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
||||
Fixed name matching error on the 13 character boundary.
|
||||
Added a configuration option, _LFN_UNICODE.
|
||||
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
||||
|
||||
|
||||
R0.08 (May 15, 2010)
|
||||
Added a memory configuration option. (_USE_LFN = 3)
|
||||
Added file lock feature. (_FS_SHARE)
|
||||
Added fast seek feature. (_USE_FASTSEEK)
|
||||
Changed some types on the API, XCHAR->TCHAR.
|
||||
Changed .fname in the FILINFO structure on Unicode cfg.
|
||||
String functions support UTF-8 encoding files on Unicode cfg.
|
||||
|
||||
|
||||
R0.08a (August 16, 2010)
|
||||
Added f_getcwd(). (_FS_RPATH = 2)
|
||||
Added sector erase feature. (_USE_ERASE)
|
||||
Moved file lock semaphore table from fs object to the bss.
|
||||
Fixed f_mkfs() creates wrong FAT32 volume.
|
||||
|
||||
|
||||
R0.08b (January 15, 2011)
|
||||
Fast seek feature is also applied to f_read() and f_write().
|
||||
f_lseek() reports required table size on creating CLMP.
|
||||
Extended format syntax of f_printf().
|
||||
Ignores duplicated directory separators in given path name.
|
||||
|
||||
|
||||
R0.09 (September 06, 2011)
|
||||
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
||||
Added f_fdisk().
|
||||
|
||||
|
||||
R0.09a (August 27, 2012)
|
||||
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
||||
Changed option name _FS_SHARE to _FS_LOCK.
|
||||
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
||||
|
||||
|
||||
R0.09b (January 24, 2013)
|
||||
Added f_setlabel() and f_getlabel().
|
||||
|
||||
|
||||
R0.10 (October 02, 2013)
|
||||
Added selection of character encoding on the file. (_STRF_ENCODE)
|
||||
Added f_closedir().
|
||||
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
||||
Added forced mount feature with changes of f_mount().
|
||||
Improved behavior of volume auto detection.
|
||||
Improved write throughput of f_puts() and f_printf().
|
||||
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
|
||||
Fixed f_write() can be truncated when the file size is close to 4GB.
|
||||
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code.
|
||||
|
||||
|
||||
R0.10a (January 15, 2014)
|
||||
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
||||
Added a configuration option of minimum sector size. (_MIN_SS)
|
||||
2nd argument of f_rename() can have a drive number and it will be ignored.
|
||||
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
|
||||
Fixed f_close() invalidates the file object without volume lock.
|
||||
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
|
||||
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
||||
|
||||
|
||||
R0.10b (May 19, 2014)
|
||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
|
||||
|
||||
R0.10c (November 09, 2014)
|
||||
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
||||
Changed option name _USE_ERASE to _USE_TRIM.
|
||||
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
||||
Fixed a potential problem of FAT access that can appear on disk error.
|
||||
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
||||
|
||||
|
||||
R0.11 (February 09, 2015)
|
||||
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
||||
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
||||
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
||||
----------------------------------------------------------------------------
|
||||
Revision history of FatFs module
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
R0.00 (February 26, 2006)
|
||||
|
||||
Prototype.
|
||||
|
||||
|
||||
|
||||
R0.01 (April 29, 2006)
|
||||
|
||||
The first release.
|
||||
|
||||
|
||||
|
||||
R0.02 (June 01, 2006)
|
||||
|
||||
Added FAT12 support.
|
||||
Removed unbuffered mode.
|
||||
Fixed a problem on small (<32M) partition.
|
||||
|
||||
|
||||
|
||||
R0.02a (June 10, 2006)
|
||||
|
||||
Added a configuration option (_FS_MINIMUM).
|
||||
|
||||
|
||||
|
||||
R0.03 (September 22, 2006)
|
||||
|
||||
Added f_rename().
|
||||
Changed option _FS_MINIMUM to _FS_MINIMIZE.
|
||||
|
||||
|
||||
|
||||
R0.03a (December 11, 2006)
|
||||
|
||||
Improved cluster scan algorithm to write files fast.
|
||||
Fixed f_mkdir() creates incorrect directory on FAT32.
|
||||
|
||||
|
||||
|
||||
R0.04 (February 04, 2007)
|
||||
|
||||
Added f_mkfs().
|
||||
Supported multiple drive system.
|
||||
Changed some interfaces for multiple drive system.
|
||||
Changed f_mountdrv() to f_mount().
|
||||
|
||||
|
||||
|
||||
R0.04a (April 01, 2007)
|
||||
|
||||
Supported multiple partitions on a physical drive.
|
||||
Added a capability of extending file size to f_lseek().
|
||||
Added minimization level 3.
|
||||
Fixed an endian sensitive code in f_mkfs().
|
||||
|
||||
|
||||
|
||||
R0.04b (May 05, 2007)
|
||||
|
||||
Added a configuration option _USE_NTFLAG.
|
||||
Added FSINFO support.
|
||||
Fixed DBCS name can result FR_INVALID_NAME.
|
||||
Fixed short seek (<= csize) collapses the file object.
|
||||
|
||||
|
||||
|
||||
R0.05 (August 25, 2007)
|
||||
|
||||
Changed arguments of f_read(), f_write() and f_mkfs().
|
||||
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
|
||||
Fixed f_mkdir() on FAT32 creates incorrect directory.
|
||||
|
||||
|
||||
|
||||
R0.05a (February 03, 2008)
|
||||
|
||||
Added f_truncate() and f_utime().
|
||||
Fixed off by one error at FAT sub-type determination.
|
||||
Fixed btr in f_read() can be mistruncated.
|
||||
Fixed cached sector is not flushed when create and close without write.
|
||||
|
||||
|
||||
|
||||
R0.06 (April 01, 2008)
|
||||
|
||||
Added fputc(), fputs(), fprintf() and fgets().
|
||||
Improved performance of f_lseek() on moving to the same or following cluster.
|
||||
|
||||
|
||||
|
||||
R0.07 (April 01, 2009)
|
||||
|
||||
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
|
||||
Added long file name feature. (_USE_LFN)
|
||||
Added multiple code page feature. (_CODE_PAGE)
|
||||
Added re-entrancy for multitask operation. (_FS_REENTRANT)
|
||||
Added auto cluster size selection to f_mkfs().
|
||||
Added rewind option to f_readdir().
|
||||
Changed result code of critical errors.
|
||||
Renamed string functions to avoid name collision.
|
||||
|
||||
|
||||
|
||||
R0.07a (April 14, 2009)
|
||||
|
||||
Septemberarated out OS dependent code on reentrant cfg.
|
||||
Added multiple sector size feature.
|
||||
|
||||
|
||||
|
||||
R0.07c (June 21, 2009)
|
||||
|
||||
Fixed f_unlink() can return FR_OK on error.
|
||||
Fixed wrong cache control in f_lseek().
|
||||
Added relative path feature.
|
||||
Added f_chdir() and f_chdrive().
|
||||
Added proper case conversion to extended character.
|
||||
|
||||
|
||||
|
||||
R0.07e (November 03, 2009)
|
||||
|
||||
Septemberarated out configuration options from ff.h to ffconf.h.
|
||||
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
|
||||
Fixed name matching error on the 13 character boundary.
|
||||
Added a configuration option, _LFN_UNICODE.
|
||||
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
|
||||
|
||||
|
||||
|
||||
R0.08 (May 15, 2010)
|
||||
|
||||
Added a memory configuration option. (_USE_LFN = 3)
|
||||
Added file lock feature. (_FS_SHARE)
|
||||
Added fast seek feature. (_USE_FASTSEEK)
|
||||
Changed some types on the API, XCHAR->TCHAR.
|
||||
Changed .fname in the FILINFO structure on Unicode cfg.
|
||||
String functions support UTF-8 encoding files on Unicode cfg.
|
||||
|
||||
|
||||
|
||||
R0.08a (August 16, 2010)
|
||||
|
||||
Added f_getcwd(). (_FS_RPATH = 2)
|
||||
Added sector erase feature. (_USE_ERASE)
|
||||
Moved file lock semaphore table from fs object to the bss.
|
||||
Fixed f_mkfs() creates wrong FAT32 volume.
|
||||
|
||||
|
||||
|
||||
R0.08b (January 15, 2011)
|
||||
|
||||
Fast seek feature is also applied to f_read() and f_write().
|
||||
f_lseek() reports required table size on creating CLMP.
|
||||
Extended format syntax of f_printf().
|
||||
Ignores duplicated directory separators in given path name.
|
||||
|
||||
|
||||
|
||||
R0.09 (September 06, 2011)
|
||||
|
||||
f_mkfs() supports multiple partition to complete the multiple partition feature.
|
||||
Added f_fdisk().
|
||||
|
||||
|
||||
|
||||
R0.09a (August 27, 2012)
|
||||
|
||||
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
|
||||
Changed option name _FS_SHARE to _FS_LOCK.
|
||||
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
|
||||
|
||||
|
||||
|
||||
R0.09b (January 24, 2013)
|
||||
|
||||
Added f_setlabel() and f_getlabel().
|
||||
|
||||
|
||||
|
||||
R0.10 (October 02, 2013)
|
||||
|
||||
Added selection of character encoding on the file. (_STRF_ENCODE)
|
||||
Added f_closedir().
|
||||
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
|
||||
Added forced mount feature with changes of f_mount().
|
||||
Improved behavior of volume auto detection.
|
||||
Improved write throughput of f_puts() and f_printf().
|
||||
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
|
||||
Fixed f_write() can be truncated when the file size is close to 4GB.
|
||||
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect value on error.
|
||||
|
||||
|
||||
|
||||
R0.10a (January 15, 2014)
|
||||
|
||||
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
|
||||
Added a configuration option of minimum sector size. (_MIN_SS)
|
||||
2nd argument of f_rename() can have a drive number and it will be ignored.
|
||||
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
|
||||
Fixed f_close() invalidates the file object without volume lock.
|
||||
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
|
||||
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10b (May 19, 2014)
|
||||
|
||||
Fixed a hard error in the disk I/O layer can collapse the directory entry.
|
||||
Fixed LFN entry is not deleted when delete/rename an object with lossy converted SFN. (appeared at R0.07)
|
||||
|
||||
|
||||
|
||||
R0.10c (November 09, 2014)
|
||||
|
||||
Added a configuration option for the platforms without RTC. (_FS_NORTC)
|
||||
Changed option name _USE_ERASE to _USE_TRIM.
|
||||
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
|
||||
Fixed a potential problem of FAT access that can appear on disk error.
|
||||
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
|
||||
|
||||
|
||||
|
||||
R0.11 (February 09, 2015)
|
||||
|
||||
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
|
||||
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
|
||||
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
|
||||
|
||||
|
||||
|
||||
R0.11a (September 05, 2015)
|
||||
|
||||
Fixed wrong media change can lead a deadlock at thread-safe configuration.
|
||||
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
|
||||
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
|
||||
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
|
||||
Fixed errors in the case conversion teble of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12 (April 12, 2016)
|
||||
|
||||
Added support for exFAT file system. (_FS_EXFAT)
|
||||
Added f_expand(). (_USE_EXPAND)
|
||||
Changed some members in FINFO structure and behavior of f_readdir().
|
||||
Added an option _USE_CHMOD.
|
||||
Removed an option _WORD_ACCESS.
|
||||
Fixed errors in the case conversion table of Unicode (cc*.c).
|
||||
|
||||
|
||||
|
||||
R0.12a (July 10, 2016)
|
||||
|
||||
Added support for creating exFAT volume with some changes of f_mkfs().
|
||||
Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
|
||||
f_forward() is available regardless of _FS_TINY.
|
||||
Fixed f_mkfs() creates wrong volume. (appeared at R0.12)
|
||||
Fixed wrong memory read in create_name(). (appeared at R0.12)
|
||||
Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
|
||||
|
||||
|
||||
|
||||
R0.12b (September 04, 2016)
|
||||
|
||||
Made f_rename() be able to rename objects with the same name but case.
|
||||
Fixed an error in the case conversion teble of code page 866. (ff.c)
|
||||
Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
|
||||
Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
|
||||
Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12)
|
||||
Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12)
|
||||
Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
|
||||
Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
|
||||
|
||||
|
||||
|
||||
R0.12c (March 04, 2017)
|
||||
|
||||
Improved write throughput at the fragmented file on the exFAT volume.
|
||||
Made memory usage for exFAT be able to be reduced as decreasing _MAX_LFN.
|
||||
Fixed successive f_getfree() can return wrong count on the FAT12/16 volume. (appeared at R0.12)
|
||||
Fixed configuration option _VOLUMES cannot be set 10. (appeared at R0.10c)
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
FatFs Module Source Files R0.11
|
||||
|
||||
|
||||
FILES
|
||||
|
||||
00readme.txt This file.
|
||||
history.txt Revision history.
|
||||
ffconf.h Configuration file for FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
ff.c FatFs module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
integer.h Integer type definitions for FatFs.
|
||||
option Optional external functions.
|
||||
|
||||
|
||||
Low level disk I/O module is not included in this archive because the FatFs
|
||||
module is only a generic file system layer and not depend on any specific
|
||||
storage device. You have to provide a low level disk I/O module that written
|
||||
to control the target storage device.
|
||||
|
||||
FatFs Module Source Files R0.12c
|
||||
|
||||
|
||||
FILES
|
||||
|
||||
00readme.txt This file.
|
||||
00history.txt Revision history.
|
||||
ff.c FatFs module.
|
||||
ffconf.h Configuration file of FatFs module.
|
||||
ff.h Common include file for FatFs and application module.
|
||||
diskio.h Common include file for FatFs and disk I/O module.
|
||||
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
|
||||
integer.h Integer type definitions for FatFs.
|
||||
option Optional external modules.
|
||||
|
||||
|
||||
Low level disk I/O module is not included in this archive because the FatFs
|
||||
module is only a generic file system layer and it does not depend on any specific
|
||||
storage device. You have to provide a low level disk I/O module written to
|
||||
control the storage device that attached to the target system.
|
||||
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
|
||||
#include "diskio.h" /* FatFs lower layer API */
|
||||
#include "sdmmc/sdmmc.h"
|
||||
#include "../crypto.h"
|
||||
|
||||
/* Definitions of physical drive number for each media */
|
||||
#define SDCARD 0
|
||||
#define CTRNAND 1
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Get Drive Status */
|
||||
@@ -30,12 +34,15 @@ DSTATUS disk_status (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DSTATUS disk_initialize (
|
||||
__attribute__((unused))
|
||||
BYTE pdrv /* Physical drive nmuber to identify the drive */
|
||||
)
|
||||
{
|
||||
sdmmc_sdcard_init();
|
||||
return RES_OK;
|
||||
static u32 sdmmcInitResult = 4;
|
||||
|
||||
if(sdmmcInitResult == 4) sdmmcInitResult = sdmmc_sdcard_init();
|
||||
|
||||
return ((pdrv == SDCARD && !(sdmmcInitResult & 2)) ||
|
||||
(pdrv == CTRNAND && !(sdmmcInitResult & 1) && !ctrNandInit())) ? 0 : STA_NOINIT;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,18 +52,14 @@ DSTATUS disk_initialize (
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
DRESULT disk_read (
|
||||
__attribute__((unused))
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
BYTE *buff, /* Data buffer to store read data */
|
||||
DWORD sector, /* Sector address in LBA */
|
||||
UINT count /* Number of sectors to read */
|
||||
)
|
||||
{
|
||||
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
return ((pdrv == SDCARD && !sdmmc_sdcard_readsectors(sector, count, buff)) ||
|
||||
(pdrv == CTRNAND && !ctrNandRead(sector, count, buff))) ? RES_OK : RES_PARERR;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,18 +70,14 @@ DRESULT disk_read (
|
||||
|
||||
#if _USE_WRITE
|
||||
DRESULT disk_write (
|
||||
__attribute__((unused))
|
||||
BYTE pdrv, /* Physical drive nmuber to identify the drive */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
const BYTE *buff, /* Data to be written */
|
||||
DWORD sector, /* Sector address in LBA */
|
||||
UINT count /* Number of sectors to write */
|
||||
)
|
||||
{
|
||||
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
|
||||
return RES_PARERR;
|
||||
}
|
||||
|
||||
return RES_OK;
|
||||
return ((pdrv == SDCARD && !sdmmc_sdcard_writesectors(sector, count, buff)) ||
|
||||
(pdrv == CTRNAND && !ctrNandWrite(sector, count, buff))) ? RES_OK : RES_PARERR;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
10836
source/fatfs/ff.c
10836
source/fatfs/ff.c
File diff suppressed because it is too large
Load Diff
@@ -1,350 +1,361 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015
|
||||
/----------------------------------------------------------------------------/
|
||||
/ FatFs module is a free software that opened under license policy of
|
||||
/ following conditions.
|
||||
/
|
||||
/ Copyright (C) 2015, ChaN, all right reserved.
|
||||
/
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef _FATFS
|
||||
#define _FATFS 32020 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "integer.h" /* Basic integer types */
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
#if _FATFS != _FFCONF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if _MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
|
||||
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
|
||||
|
||||
#else /* Single partition configuration */
|
||||
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
|
||||
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#if _LFN_UNICODE /* Unicode string */
|
||||
#if !_USE_LFN
|
||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||
#endif
|
||||
#ifndef _INC_TCHAR
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#endif
|
||||
|
||||
#else /* ANSI/OEM string */
|
||||
#ifndef _INC_TCHAR
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* File system object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
|
||||
BYTE drv; /* Physical drive number */
|
||||
BYTE csize; /* Sectors per cluster (1,2,4...128) */
|
||||
BYTE n_fats; /* Number of FAT copies (1 or 2) */
|
||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||
WORD id; /* File system mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
#if _MAX_SS != _MIN_SS
|
||||
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if _FS_REENTRANT
|
||||
_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !_FS_READONLY
|
||||
DWORD last_clust; /* Last allocated cluster */
|
||||
DWORD free_clust; /* Number of free clusters */
|
||||
#endif
|
||||
#if _FS_RPATH
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */
|
||||
DWORD fsize; /* Sectors per FAT */
|
||||
DWORD volbase; /* Volume start sector */
|
||||
DWORD fatbase; /* FAT start sector */
|
||||
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
|
||||
DWORD database; /* Data start sector */
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */
|
||||
WORD id; /* Owner file system mount ID (**do not change order**) */
|
||||
BYTE flag; /* Status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD fsize; /* File size */
|
||||
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
|
||||
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
|
||||
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
||||
#endif
|
||||
#if _USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
|
||||
#endif
|
||||
#if _FS_LOCK
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
#if !_FS_TINY
|
||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */
|
||||
WORD id; /* Owner file system mount ID (**do not change order**) */
|
||||
WORD index; /* Current read/write index number */
|
||||
DWORD sclust; /* Table start cluster (0:Root dir) */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector */
|
||||
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
|
||||
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
|
||||
#if _FS_LOCK
|
||||
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
#if _USE_LFN
|
||||
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
||||
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
|
||||
#endif
|
||||
#if _USE_FIND
|
||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File information structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
DWORD fsize; /* File size */
|
||||
WORD fdate; /* Last modified date */
|
||||
WORD ftime; /* Last modified time */
|
||||
BYTE fattrib; /* Attribute */
|
||||
TCHAR fname[13]; /* Short file name (8.3 format) */
|
||||
#if _USE_LFN
|
||||
TCHAR* lfname; /* Pointer to the LFN buffer */
|
||||
UINT lfsize; /* Size of LFN buffer in TCHAR */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs module application interface */
|
||||
|
||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
|
||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
|
||||
FRESULT f_truncate (FIL* fp); /* Truncate file */
|
||||
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
|
||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
||||
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
|
||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */
|
||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
|
||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||
|
||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
|
||||
#define f_error(fp) ((fp)->err)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->fsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional user defined functions */
|
||||
|
||||
/* RTC function */
|
||||
#if !_FS_READONLY && !_FS_NORTC
|
||||
DWORD get_fattime (void);
|
||||
#endif
|
||||
|
||||
/* Unicode support functions */
|
||||
#if _USE_LFN /* Unicode - OEM code conversion */
|
||||
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
|
||||
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
|
||||
#if _USE_LFN == 3 /* Memory functions */
|
||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||
void ff_memfree (void* mblock); /* Free memory block */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sync functions */
|
||||
#if _FS_REENTRANT
|
||||
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
|
||||
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
|
||||
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
|
||||
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and offset address */
|
||||
|
||||
|
||||
/* File access control and file status flags (FIL.flag) */
|
||||
|
||||
#define FA_READ 0x01
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
|
||||
#if !_FS_READONLY
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA__WRITTEN 0x20
|
||||
#define FA__DIRTY 0x40
|
||||
#endif
|
||||
|
||||
|
||||
/* FAT sub type (FATFS.fs_type) */
|
||||
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
|
||||
|
||||
/* File attribute bits for directory entry */
|
||||
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_VOL 0x08 /* Volume label */
|
||||
#define AM_LFN 0x0F /* LFN entry */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||
|
||||
|
||||
/* Fast seek feature */
|
||||
#define CREATE_LINKMAP 0xFFFFFFFF
|
||||
|
||||
|
||||
|
||||
/*--------------------------------*/
|
||||
/* Multi-byte word access macros */
|
||||
|
||||
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
|
||||
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
|
||||
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
|
||||
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
|
||||
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
|
||||
#else /* Use byte-by-byte access to the FAT structure */
|
||||
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
|
||||
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
|
||||
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
|
||||
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FATFS */
|
||||
/*----------------------------------------------------------------------------/
|
||||
/ FatFs - Generic FAT file system module R0.12c /
|
||||
/-----------------------------------------------------------------------------/
|
||||
/
|
||||
/ Copyright (C) 2017, ChaN, all right reserved.
|
||||
/
|
||||
/ FatFs module is an open source software. Redistribution and use of FatFs in
|
||||
/ source and binary forms, with or without modification, are permitted provided
|
||||
/ that the following condition is met:
|
||||
|
||||
/ 1. Redistributions of source code must retain the above copyright notice,
|
||||
/ this condition and the following disclaimer.
|
||||
/
|
||||
/ This software is provided by the copyright holder and contributors "AS IS"
|
||||
/ and any warranties related to this software are DISCLAIMED.
|
||||
/ The copyright owner or contributors be NOT LIABLE for any damages caused
|
||||
/ by use of this software.
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef _FATFS
|
||||
#define _FATFS 68300 /* Revision ID */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "integer.h" /* Basic integer types */
|
||||
#include "ffconf.h" /* FatFs configuration options */
|
||||
|
||||
#if _FATFS != _FFCONF
|
||||
#error Wrong configuration file (ffconf.h).
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Definitions of volume management */
|
||||
|
||||
#if _MULTI_PARTITION /* Multiple partition configuration */
|
||||
typedef struct {
|
||||
BYTE pd; /* Physical drive number */
|
||||
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
|
||||
} PARTITION;
|
||||
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of path name strings on FatFs API */
|
||||
|
||||
#if _LFN_UNICODE /* Unicode (UTF-16) string */
|
||||
#if _USE_LFN == 0
|
||||
#error _LFN_UNICODE must be 0 at non-LFN cfg.
|
||||
#endif
|
||||
#ifndef _INC_TCHAR
|
||||
typedef WCHAR TCHAR;
|
||||
#define _T(x) L ## x
|
||||
#define _TEXT(x) L ## x
|
||||
#endif
|
||||
#else /* ANSI/OEM string */
|
||||
#ifndef _INC_TCHAR
|
||||
typedef char TCHAR;
|
||||
#define _T(x) x
|
||||
#define _TEXT(x) x
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* Type of file size variables */
|
||||
|
||||
#if _FS_EXFAT
|
||||
#if _USE_LFN == 0
|
||||
#error LFN must be enabled when enable exFAT
|
||||
#endif
|
||||
typedef QWORD FSIZE_t;
|
||||
#else
|
||||
typedef DWORD FSIZE_t;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* File system object structure (FATFS) */
|
||||
|
||||
typedef struct {
|
||||
BYTE fs_type; /* File system type (0:N/A) */
|
||||
BYTE drv; /* Physical drive number */
|
||||
BYTE n_fats; /* Number of FATs (1 or 2) */
|
||||
BYTE wflag; /* win[] flag (b0:dirty) */
|
||||
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
|
||||
WORD id; /* File system mount ID */
|
||||
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
|
||||
WORD csize; /* Cluster size [sectors] */
|
||||
#if _MAX_SS != _MIN_SS
|
||||
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
|
||||
#endif
|
||||
#if _USE_LFN != 0
|
||||
WCHAR* lfnbuf; /* LFN working buffer */
|
||||
#endif
|
||||
#if _FS_EXFAT
|
||||
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
|
||||
#endif
|
||||
#if _FS_REENTRANT
|
||||
_SYNC_t sobj; /* Identifier of sync object */
|
||||
#endif
|
||||
#if !_FS_READONLY
|
||||
DWORD last_clst; /* Last allocated cluster */
|
||||
DWORD free_clst; /* Number of free clusters */
|
||||
#endif
|
||||
#if _FS_RPATH != 0
|
||||
DWORD cdir; /* Current directory start cluster (0:root) */
|
||||
#if _FS_EXFAT
|
||||
DWORD cdc_scl; /* Containing directory start cluster (invalid when cdir is 0) */
|
||||
DWORD cdc_size; /* b31-b8:Size of containing directory, b7-b0: Chain status */
|
||||
DWORD cdc_ofs; /* Offset in the containing directory (invalid when cdir is 0) */
|
||||
#endif
|
||||
#endif
|
||||
DWORD n_fatent; /* Number of FAT entries (number of clusters + 2) */
|
||||
DWORD fsize; /* Size of an FAT [sectors] */
|
||||
DWORD volbase; /* Volume base sector */
|
||||
DWORD fatbase; /* FAT base sector */
|
||||
DWORD dirbase; /* Root directory base sector/cluster */
|
||||
DWORD database; /* Data base sector */
|
||||
DWORD winsect; /* Current sector appearing in the win[] */
|
||||
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
|
||||
} FATFS;
|
||||
|
||||
|
||||
|
||||
/* Object ID and allocation information (_FDID) */
|
||||
|
||||
typedef struct {
|
||||
FATFS* fs; /* Pointer to the owner file system object */
|
||||
WORD id; /* Owner file system mount ID */
|
||||
BYTE attr; /* Object attribute */
|
||||
BYTE stat; /* Object chain status (b1-0: =0:not contiguous, =2:contiguous (no data on FAT), =3:flagmented in this session, b2:sub-directory stretched) */
|
||||
DWORD sclust; /* Object start cluster (0:no cluster or root directory) */
|
||||
FSIZE_t objsize; /* Object size (valid when sclust != 0) */
|
||||
#if _FS_EXFAT
|
||||
DWORD n_cont; /* Size of first fragment, clusters - 1 (valid when stat == 3) */
|
||||
DWORD n_frag; /* Size of last fragment needs to be written (valid when not zero) */
|
||||
DWORD c_scl; /* Containing directory start cluster (valid when sclust != 0) */
|
||||
DWORD c_size; /* b31-b8:Size of containing directory, b7-b0: Chain status (valid when c_scl != 0) */
|
||||
DWORD c_ofs; /* Offset in the containing directory (valid when sclust != 0 and non-directory object) */
|
||||
#endif
|
||||
#if _FS_LOCK != 0
|
||||
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
|
||||
#endif
|
||||
} _FDID;
|
||||
|
||||
|
||||
|
||||
/* File object structure (FIL) */
|
||||
|
||||
typedef struct {
|
||||
_FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
|
||||
BYTE flag; /* File status flags */
|
||||
BYTE err; /* Abort flag (error code) */
|
||||
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
|
||||
DWORD clust; /* Current cluster of fpter (invalid when fptr is 0) */
|
||||
DWORD sect; /* Sector number appearing in buf[] (0:invalid) */
|
||||
#if !_FS_READONLY
|
||||
DWORD dir_sect; /* Sector number containing the directory entry */
|
||||
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
|
||||
#endif
|
||||
#if _USE_FASTSEEK
|
||||
DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
|
||||
#endif
|
||||
#if !_FS_TINY
|
||||
BYTE buf[_MAX_SS]; /* File private data read/write window */
|
||||
#endif
|
||||
} FIL;
|
||||
|
||||
|
||||
|
||||
/* Directory object structure (DIR) */
|
||||
|
||||
typedef struct {
|
||||
_FDID obj; /* Object identifier */
|
||||
DWORD dptr; /* Current read/write offset */
|
||||
DWORD clust; /* Current cluster */
|
||||
DWORD sect; /* Current sector (0:Read operation has terminated) */
|
||||
BYTE* dir; /* Pointer to the directory item in the win[] */
|
||||
BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
|
||||
#if _USE_LFN != 0
|
||||
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
|
||||
#endif
|
||||
#if _USE_FIND
|
||||
const TCHAR* pat; /* Pointer to the name matching pattern */
|
||||
#endif
|
||||
} DIR;
|
||||
|
||||
|
||||
|
||||
/* File information structure (FILINFO) */
|
||||
|
||||
typedef struct {
|
||||
FSIZE_t fsize; /* File size */
|
||||
WORD fdate; /* Modified date */
|
||||
WORD ftime; /* Modified time */
|
||||
BYTE fattrib; /* File attribute */
|
||||
#if _USE_LFN != 0
|
||||
TCHAR altname[13]; /* Altenative file name */
|
||||
TCHAR fname[_MAX_LFN + 1]; /* Primary file name */
|
||||
#else
|
||||
TCHAR fname[13]; /* File name */
|
||||
#endif
|
||||
} FILINFO;
|
||||
|
||||
|
||||
|
||||
/* File function return code (FRESULT) */
|
||||
|
||||
typedef enum {
|
||||
FR_OK = 0, /* (0) Succeeded */
|
||||
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
|
||||
FR_INT_ERR, /* (2) Assertion failed */
|
||||
FR_NOT_READY, /* (3) The physical drive cannot work */
|
||||
FR_NO_FILE, /* (4) Could not find the file */
|
||||
FR_NO_PATH, /* (5) Could not find the path */
|
||||
FR_INVALID_NAME, /* (6) The path name format is invalid */
|
||||
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
|
||||
FR_EXIST, /* (8) Access denied due to prohibited access */
|
||||
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
|
||||
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
|
||||
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
|
||||
FR_NOT_ENABLED, /* (12) The volume has no work area */
|
||||
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
|
||||
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
|
||||
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
|
||||
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
|
||||
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
|
||||
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
|
||||
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
|
||||
} FRESULT;
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* FatFs module application interface */
|
||||
|
||||
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
|
||||
FRESULT f_close (FIL* fp); /* Close an open file object */
|
||||
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
|
||||
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
|
||||
FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
|
||||
FRESULT f_truncate (FIL* fp); /* Truncate the file */
|
||||
FRESULT f_sync (FIL* fp); /* Flush cached data of the writing file */
|
||||
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
|
||||
FRESULT f_closedir (DIR* dp); /* Close an open directory */
|
||||
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
|
||||
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
|
||||
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
|
||||
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
|
||||
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
|
||||
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
|
||||
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
|
||||
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
|
||||
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a file/dir */
|
||||
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
|
||||
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
|
||||
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
|
||||
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
|
||||
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
|
||||
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
|
||||
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
|
||||
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
|
||||
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
|
||||
FRESULT f_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
|
||||
FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
|
||||
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
|
||||
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
|
||||
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
|
||||
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
|
||||
|
||||
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
|
||||
#define f_error(fp) ((fp)->err)
|
||||
#define f_tell(fp) ((fp)->fptr)
|
||||
#define f_size(fp) ((fp)->obj.objsize)
|
||||
#define f_rewind(fp) f_lseek((fp), 0)
|
||||
#define f_rewinddir(dp) f_readdir((dp), 0)
|
||||
#define f_rmdir(path) f_unlink(path)
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF (-1)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Additional user defined functions */
|
||||
|
||||
/* RTC function */
|
||||
#if !_FS_READONLY && !_FS_NORTC
|
||||
DWORD get_fattime (void);
|
||||
#endif
|
||||
|
||||
/* Unicode support functions */
|
||||
#if _USE_LFN != 0 /* Unicode - OEM code conversion */
|
||||
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
|
||||
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
|
||||
#if _USE_LFN == 3 /* Memory functions */
|
||||
void* ff_memalloc (UINT msize); /* Allocate memory block */
|
||||
void ff_memfree (void* mblock); /* Free memory block */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Sync functions */
|
||||
#if _FS_REENTRANT
|
||||
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
|
||||
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
|
||||
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
|
||||
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/*--------------------------------------------------------------*/
|
||||
/* Flags and offset address */
|
||||
|
||||
|
||||
/* File access mode and open method flags (3rd argument of f_open) */
|
||||
#define FA_READ 0x01
|
||||
#define FA_WRITE 0x02
|
||||
#define FA_OPEN_EXISTING 0x00
|
||||
#define FA_CREATE_NEW 0x04
|
||||
#define FA_CREATE_ALWAYS 0x08
|
||||
#define FA_OPEN_ALWAYS 0x10
|
||||
#define FA_OPEN_APPEND 0x30
|
||||
|
||||
/* Fast seek controls (2nd argument of f_lseek) */
|
||||
#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
|
||||
|
||||
/* Format options (2nd argument of f_mkfs) */
|
||||
#define FM_FAT 0x01
|
||||
#define FM_FAT32 0x02
|
||||
#define FM_EXFAT 0x04
|
||||
#define FM_ANY 0x07
|
||||
#define FM_SFD 0x08
|
||||
|
||||
/* Filesystem type (FATFS.fs_type) */
|
||||
#define FS_FAT12 1
|
||||
#define FS_FAT16 2
|
||||
#define FS_FAT32 3
|
||||
#define FS_EXFAT 4
|
||||
|
||||
/* File attribute bits for directory entry (FILINFO.fattrib) */
|
||||
#define AM_RDO 0x01 /* Read only */
|
||||
#define AM_HID 0x02 /* Hidden */
|
||||
#define AM_SYS 0x04 /* System */
|
||||
#define AM_DIR 0x10 /* Directory */
|
||||
#define AM_ARC 0x20 /* Archive */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _FATFS */
|
||||
|
||||
@@ -1,271 +1,268 @@
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 32020 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Functions and Buffer Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
|
||||
/ bytes. Instead of private sector buffer eliminated from the file object,
|
||||
/ common sector buffer in the file system object (FATFS) is used for the file
|
||||
/ data transfer. */
|
||||
|
||||
|
||||
#define _FS_READONLY 0
|
||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define _FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: All basic functions are enabled.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
|
||||
/ f_truncate() and f_rename() function are removed.
|
||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define _USE_STRFUNC 0
|
||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
|
||||
/ f_printf().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
/ 1: Enable without LF-CRLF conversion.
|
||||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define _USE_FIND 0
|
||||
/* This option switches filtered directory read feature and related functions,
|
||||
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_MKFS 0
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_FASTSEEK 0
|
||||
/* This option switches fast seek feature. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable)
|
||||
/ To enable it, also _FS_TINY need to be set to 1. */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _CODE_PAGE 437
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect setting of the code page can cause a file open failure.
|
||||
/
|
||||
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
/ 775 - Baltic
|
||||
/ 850 - Multilingual Latin 1
|
||||
/ 852 - Latin 2
|
||||
/ 855 - Cyrillic
|
||||
/ 857 - Turkish
|
||||
/ 858 - Multilingual Latin 1 + Euro
|
||||
/ 862 - Hebrew
|
||||
/ 866 - Russian
|
||||
/ 874 - Thai
|
||||
/ 932 - Japanese Shift_JIS (DBCS)
|
||||
/ 936 - Simplified Chinese GBK (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese Big5 (DBCS)
|
||||
*/
|
||||
|
||||
|
||||
#define _USE_LFN 2
|
||||
#define _MAX_LFN 255
|
||||
/* The _USE_LFN option switches the LFN feature.
|
||||
/
|
||||
/ 0: Disable LFN feature. _MAX_LFN has no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
|
||||
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
|
||||
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||
/ ff_memfree(), must be added to the project. */
|
||||
|
||||
|
||||
#define _LFN_UNICODE 0
|
||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
|
||||
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
|
||||
/ to 1. This option also affects behavior of string I/O functions. */
|
||||
|
||||
|
||||
#define _STRF_ENCODE 0
|
||||
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
|
||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||
/
|
||||
/ 0: ANSI/OEM
|
||||
/ 1: UTF-16LE
|
||||
/ 2: UTF-16BE
|
||||
/ 3: UTF-8
|
||||
/
|
||||
/ When _LFN_UNICODE is 0, this option has no effect. */
|
||||
|
||||
|
||||
#define _FS_RPATH 0
|
||||
/* This option configures relative path feature.
|
||||
/
|
||||
/ 0: Disable relative path feature and remove related functions.
|
||||
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
|
||||
/ 2: f_getcwd() function is available in addition to 1.
|
||||
/
|
||||
/ Note that directory items read via f_readdir() are affected by this option. */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 1
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
|
||||
/* _STR_VOLUME_ID option switches string volume ID feature.
|
||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
|
||||
/ the drive ID strings are: A-Z and 0-9. */
|
||||
|
||||
|
||||
#define _MULTI_PARTITION 0
|
||||
/* This option switches multi-partition feature. By default (0), each logical drive
|
||||
/ number is bound to the same physical drive number and only an FAT volume found on
|
||||
/ the physical drive will be mounted. When multi-partition feature is enabled (1),
|
||||
/ each logical drive number is bound to arbitrary physical drive and partition
|
||||
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
|
||||
|
||||
|
||||
#define _MIN_SS 512
|
||||
#define _MAX_SS 512
|
||||
/* These options configure the range of sector size to be supported. (512, 1024,
|
||||
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _USE_TRIM 0
|
||||
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
|
||||
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _FS_NOFSINFO 0
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
/
|
||||
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_NORTC 1
|
||||
#define _NORTC_MON 2
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2015
|
||||
/* The _FS_NORTC option switches timestamp feature. If the system does not have
|
||||
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
|
||||
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
|
||||
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
|
||||
/ to be added to the project to read current time form RTC. _NORTC_MON,
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
|
||||
|
||||
|
||||
#define _FS_LOCK 0
|
||||
/* The _FS_LOCK option switches file lock feature to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
|
||||
/ is 1.
|
||||
/
|
||||
/ 0: Disable file lock feature. To avoid volume corruption, application program
|
||||
/ should avoid illegal open, remove and rename to the open objects.
|
||||
/ >0: Enable file lock feature. The value defines how many files/sub-directories
|
||||
/ can be opened simultaneously under file lock control. Note that the file
|
||||
/ lock feature is independent of re-entrancy. */
|
||||
|
||||
|
||||
#define _FS_REENTRANT 0
|
||||
#define _FS_TIMEOUT 1000
|
||||
#define _SYNC_t HANDLE
|
||||
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
|
||||
/ module itself. Note that regardless of this option, file access to different
|
||||
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||
/ to the same volume is under control of this feature.
|
||||
/
|
||||
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
|
||||
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
|
||||
/ function, must be added to the project. Samples are available in
|
||||
/ option/syscall.c.
|
||||
/
|
||||
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.c. */
|
||||
|
||||
|
||||
#define _WORD_ACCESS 0
|
||||
/* The _WORD_ACCESS option is an only platform dependent option. It defines
|
||||
/ which access method is used to the word data on the FAT volume.
|
||||
/
|
||||
/ 0: Byte-by-byte access. Always compatible with all platforms.
|
||||
/ 1: Word access. Do not choose this unless under both the following conditions.
|
||||
/
|
||||
/ * Address misaligned memory access is always allowed to ALL instructions.
|
||||
/ * Byte order on the memory is little-endian.
|
||||
/
|
||||
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
|
||||
/ Following table shows allowable settings of some processor types.
|
||||
/
|
||||
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
|
||||
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
|
||||
/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1
|
||||
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
|
||||
/ AVR32 0 *1 RL78 0 *2 R32C 0 *2
|
||||
/ PIC18 0/1 SH-2 0 *1 M16C 0/1
|
||||
/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
|
||||
/ PIC32 0 *1 H8/300H 0 *1 8051 0/1
|
||||
/
|
||||
/ *1:Big-endian.
|
||||
/ *2:Unaligned memory access is not supported.
|
||||
/ *3:Some compilers generate LDM/STM for mem_cpy function.
|
||||
*/
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ FatFs - FAT file system module configuration file
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FFCONF 68300 /* Revision ID */
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Function Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_READONLY 0
|
||||
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
|
||||
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
|
||||
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
|
||||
/ and optional writing functions as well. */
|
||||
|
||||
|
||||
#define _FS_MINIMIZE 0
|
||||
/* This option defines minimization level to remove some basic API functions.
|
||||
/
|
||||
/ 0: All basic functions are enabled.
|
||||
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_truncate() and f_rename()
|
||||
/ are removed.
|
||||
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
|
||||
/ 3: f_lseek() function is removed in addition to 2. */
|
||||
|
||||
|
||||
#define _USE_STRFUNC 0
|
||||
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
|
||||
/ f_printf().
|
||||
/
|
||||
/ 0: Disable string functions.
|
||||
/ 1: Enable without LF-CRLF conversion.
|
||||
/ 2: Enable with LF-CRLF conversion. */
|
||||
|
||||
|
||||
#define _USE_FIND 1
|
||||
/* This option switches filtered directory read functions, f_findfirst() and
|
||||
/ f_findnext(). (0:Disable, 1:Enable 2:Enable with matching altname[] too) */
|
||||
|
||||
|
||||
#define _USE_MKFS 0
|
||||
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_FASTSEEK 0
|
||||
/* This option switches fast seek function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_EXPAND 0
|
||||
/* This option switches f_expand function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_CHMOD 0
|
||||
/* This option switches attribute manipulation functions, f_chmod() and f_utime().
|
||||
/ (0:Disable or 1:Enable) Also _FS_READONLY needs to be 0 to enable this option. */
|
||||
|
||||
|
||||
#define _USE_LABEL 0
|
||||
/* This option switches volume label functions, f_getlabel() and f_setlabel().
|
||||
/ (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
#define _USE_FORWARD 0
|
||||
/* This option switches f_forward() function. (0:Disable or 1:Enable) */
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Locale and Namespace Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _CODE_PAGE 437
|
||||
/* This option specifies the OEM code page to be used on the target system.
|
||||
/ Incorrect setting of the code page can cause a file open failure.
|
||||
/
|
||||
/ 1 - ASCII (No support of extended character. Non-LFN cfg. only)
|
||||
/ 437 - U.S.
|
||||
/ 720 - Arabic
|
||||
/ 737 - Greek
|
||||
/ 771 - KBL
|
||||
/ 775 - Baltic
|
||||
/ 850 - Latin 1
|
||||
/ 852 - Latin 2
|
||||
/ 855 - Cyrillic
|
||||
/ 857 - Turkish
|
||||
/ 860 - Portuguese
|
||||
/ 861 - Icelandic
|
||||
/ 862 - Hebrew
|
||||
/ 863 - Canadian French
|
||||
/ 864 - Arabic
|
||||
/ 865 - Nordic
|
||||
/ 866 - Russian
|
||||
/ 869 - Greek 2
|
||||
/ 932 - Japanese (DBCS)
|
||||
/ 936 - Simplified Chinese (DBCS)
|
||||
/ 949 - Korean (DBCS)
|
||||
/ 950 - Traditional Chinese (DBCS)
|
||||
*/
|
||||
|
||||
|
||||
#define _USE_LFN 2
|
||||
#define _MAX_LFN 255
|
||||
/* The _USE_LFN switches the support of long file name (LFN).
|
||||
/
|
||||
/ 0: Disable support of LFN. _MAX_LFN has no effect.
|
||||
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
|
||||
/ 2: Enable LFN with dynamic working buffer on the STACK.
|
||||
/ 3: Enable LFN with dynamic working buffer on the HEAP.
|
||||
/
|
||||
/ To enable the LFN, Unicode handling functions (option/unicode.c) must be added
|
||||
/ to the project. The working buffer occupies (_MAX_LFN + 1) * 2 bytes and
|
||||
/ additional 608 bytes at exFAT enabled. _MAX_LFN can be in range from 12 to 255.
|
||||
/ It should be set 255 to support full featured LFN operations.
|
||||
/ When use stack for the working buffer, take care on stack overflow. When use heap
|
||||
/ memory for the working buffer, memory management functions, ff_memalloc() and
|
||||
/ ff_memfree(), must be added to the project. */
|
||||
|
||||
|
||||
#define _LFN_UNICODE 0
|
||||
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
|
||||
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
|
||||
/ This option also affects behavior of string I/O functions. */
|
||||
|
||||
|
||||
#define _STRF_ENCODE 3
|
||||
/* When _LFN_UNICODE == 1, this option selects the character encoding ON THE FILE to
|
||||
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
|
||||
/
|
||||
/ 0: ANSI/OEM
|
||||
/ 1: UTF-16LE
|
||||
/ 2: UTF-16BE
|
||||
/ 3: UTF-8
|
||||
/
|
||||
/ This option has no effect when _LFN_UNICODE == 0. */
|
||||
|
||||
|
||||
#define _FS_RPATH 1
|
||||
/* This option configures support of relative path.
|
||||
/
|
||||
/ 0: Disable relative path and remove related functions.
|
||||
/ 1: Enable relative path. f_chdir() and f_chdrive() are available.
|
||||
/ 2: f_getcwd() function is available in addition to 1.
|
||||
*/
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ Drive/Volume Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _VOLUMES 2
|
||||
/* Number of volumes (logical drives) to be used. (1-10) */
|
||||
|
||||
|
||||
#define _STR_VOLUME_ID 0
|
||||
#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
|
||||
/* _STR_VOLUME_ID switches string support of volume ID.
|
||||
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
|
||||
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
|
||||
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
|
||||
/ the drive ID strings are: A-Z and 0-9. */
|
||||
|
||||
|
||||
#define _MULTI_PARTITION 0
|
||||
/* This option switches support of multi-partition on a physical drive.
|
||||
/ By default (0), each logical drive number is bound to the same physical drive
|
||||
/ number and only an FAT volume found on the physical drive will be mounted.
|
||||
/ When multi-partition is enabled (1), each logical drive number can be bound to
|
||||
/ arbitrary physical drive and partition listed in the VolToPart[]. Also f_fdisk()
|
||||
/ funciton will be available. */
|
||||
|
||||
|
||||
#define _MIN_SS 512
|
||||
#define _MAX_SS 512
|
||||
/* These options configure the range of sector size to be supported. (512, 1024,
|
||||
/ 2048 or 4096) Always set both 512 for most systems, generic memory card and
|
||||
/ harddisk. But a larger value may be required for on-board flash memory and some
|
||||
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
|
||||
/ to variable sector size and GET_SECTOR_SIZE command needs to be implemented to
|
||||
/ the disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _USE_TRIM 0
|
||||
/* This option switches support of ATA-TRIM. (0:Disable or 1:Enable)
|
||||
/ To enable Trim function, also CTRL_TRIM command should be implemented to the
|
||||
/ disk_ioctl() function. */
|
||||
|
||||
|
||||
#define _FS_NOFSINFO 0
|
||||
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
|
||||
/ option, and f_getfree() function at first time after volume mount will force
|
||||
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
|
||||
/
|
||||
/ bit0=0: Use free cluster count in the FSINFO if available.
|
||||
/ bit0=1: Do not trust free cluster count in the FSINFO.
|
||||
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
|
||||
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*---------------------------------------------------------------------------/
|
||||
/ System Configurations
|
||||
/---------------------------------------------------------------------------*/
|
||||
|
||||
#define _FS_TINY 0
|
||||
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
|
||||
/ At the tiny configuration, size of file object (FIL) is shrinked _MAX_SS bytes.
|
||||
/ Instead of private sector buffer eliminated from the file object, common sector
|
||||
/ buffer in the file system object (FATFS) is used for the file data transfer. */
|
||||
|
||||
|
||||
#define _FS_EXFAT 0
|
||||
/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
|
||||
/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
|
||||
/ Note that enabling exFAT discards ANSI C (C89) compatibility. */
|
||||
|
||||
|
||||
#define _FS_NORTC 1
|
||||
#define _NORTC_MON 1
|
||||
#define _NORTC_MDAY 1
|
||||
#define _NORTC_YEAR 2017
|
||||
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
|
||||
/ any RTC function or valid timestamp is not needed, set _FS_NORTC = 1 to disable
|
||||
/ the timestamp function. All objects modified by FatFs will have a fixed timestamp
|
||||
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR in local time.
|
||||
/ To enable timestamp function (_FS_NORTC = 0), get_fattime() function need to be
|
||||
/ added to the project to get current time form real-time clock. _NORTC_MON,
|
||||
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
|
||||
/ These options have no effect at read-only configuration (_FS_READONLY = 1). */
|
||||
|
||||
|
||||
#define _FS_LOCK 0
|
||||
/* The option _FS_LOCK switches file lock function to control duplicated file open
|
||||
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
|
||||
/ is 1.
|
||||
/
|
||||
/ 0: Disable file lock function. To avoid volume corruption, application program
|
||||
/ should avoid illegal open, remove and rename to the open objects.
|
||||
/ >0: Enable file lock function. The value defines how many files/sub-directories
|
||||
/ can be opened simultaneously under file lock control. Note that the file
|
||||
/ lock control is independent of re-entrancy. */
|
||||
|
||||
|
||||
#define _FS_REENTRANT 0
|
||||
#define _FS_TIMEOUT 1000
|
||||
#define _SYNC_t HANDLE
|
||||
/* The option _FS_REENTRANT switches the re-entrancy (thread safe) of the FatFs
|
||||
/ module itself. Note that regardless of this option, file access to different
|
||||
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
|
||||
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
|
||||
/ to the same volume is under control of this function.
|
||||
/
|
||||
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
|
||||
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
|
||||
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
|
||||
/ function, must be added to the project. Samples are available in
|
||||
/ option/syscall.c.
|
||||
/
|
||||
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
|
||||
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
|
||||
/ SemaphoreHandle_t and etc. A header file for O/S definitions needs to be
|
||||
/ included somewhere in the scope of ff.h. */
|
||||
|
||||
/* #include <windows.h> // O/S definitions */
|
||||
|
||||
|
||||
|
||||
/*--- End of configuration options ---*/
|
||||
|
||||
@@ -1,33 +1,38 @@
|
||||
/*-------------------------------------------*/
|
||||
/* Integer type definitions for FatFs module */
|
||||
/*-------------------------------------------*/
|
||||
|
||||
#ifndef _FF_INTEGER
|
||||
#define _FF_INTEGER
|
||||
|
||||
#ifdef _WIN32 /* FatFs development platform */
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#else /* Embedded platform */
|
||||
|
||||
/* This type MUST be 8 bit */
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* These types MUST be 16 bit */
|
||||
typedef short SHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
|
||||
/* These types MUST be 16 bit or 32 bit */
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
/* These types MUST be 32 bit */
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
/*-------------------------------------------*/
|
||||
/* Integer type definitions for FatFs module */
|
||||
/*-------------------------------------------*/
|
||||
|
||||
#ifndef _FF_INTEGER
|
||||
#define _FF_INTEGER
|
||||
|
||||
#ifdef _WIN32 /* FatFs development platform */
|
||||
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
typedef unsigned __int64 QWORD;
|
||||
|
||||
|
||||
#else /* Embedded platform */
|
||||
|
||||
/* These types MUST be 16-bit or 32-bit */
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
|
||||
/* This type MUST be 8-bit */
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* These types MUST be 16-bit */
|
||||
typedef short SHORT;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned short WCHAR;
|
||||
|
||||
/* These types MUST be 32-bit */
|
||||
typedef long LONG;
|
||||
typedef unsigned long DWORD;
|
||||
|
||||
/* This type MUST be 64-bit (Remove this for ANSI C (C89) compatibility) */
|
||||
typedef unsigned long long QWORD;
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
388
source/fatfs/option/ccsbcs.c
Normal file
388
source/fatfs/option/ccsbcs.c
Normal file
@@ -0,0 +1,388 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */
|
||||
/* (SBCS code pages) */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* 437 U.S.
|
||||
/ 720 Arabic
|
||||
/ 737 Greek
|
||||
/ 771 KBL
|
||||
/ 775 Baltic
|
||||
/ 850 Latin 1
|
||||
/ 852 Latin 2
|
||||
/ 855 Cyrillic
|
||||
/ 857 Turkish
|
||||
/ 860 Portuguese
|
||||
/ 861 Icelandic
|
||||
/ 862 Hebrew
|
||||
/ 863 Canadian French
|
||||
/ 864 Arabic
|
||||
/ 865 Nordic
|
||||
/ 866 Russian
|
||||
/ 869 Greek 2
|
||||
*/
|
||||
|
||||
#include "../ff.h"
|
||||
|
||||
|
||||
#if _CODE_PAGE == 437
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 720
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
|
||||
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
|
||||
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
|
||||
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
|
||||
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 737
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
|
||||
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
|
||||
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
|
||||
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
|
||||
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 771
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */
|
||||
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
|
||||
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 775
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
|
||||
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
|
||||
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
|
||||
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
|
||||
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 850
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
|
||||
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
|
||||
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 852
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
|
||||
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
|
||||
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
|
||||
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 855
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
|
||||
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
|
||||
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
|
||||
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
|
||||
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
|
||||
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 857
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
|
||||
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
|
||||
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
|
||||
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 860
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
|
||||
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 861
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
|
||||
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 862
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
|
||||
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
|
||||
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 863
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
|
||||
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
|
||||
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 864
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */
|
||||
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
|
||||
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
|
||||
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
|
||||
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
|
||||
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
|
||||
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
|
||||
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
|
||||
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 865
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */
|
||||
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
|
||||
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
|
||||
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
|
||||
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 866
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
|
||||
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
|
||||
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
|
||||
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
|
||||
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
|
||||
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
|
||||
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#elif _CODE_PAGE == 869
|
||||
#define _TBLDEF 1
|
||||
static
|
||||
const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */
|
||||
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
|
||||
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
|
||||
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
|
||||
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
|
||||
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
|
||||
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
|
||||
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
|
||||
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !_TBLDEF || !_USE_LFN
|
||||
#error This file is not needed at current configuration. Remove from the project.
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
WCHAR ff_convert ( /* Converted character, Returns zero on error */
|
||||
WCHAR chr, /* Character code to be converted */
|
||||
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
|
||||
)
|
||||
{
|
||||
WCHAR c;
|
||||
|
||||
|
||||
if (chr < 0x80) { /* ASCII */
|
||||
c = chr;
|
||||
|
||||
} else {
|
||||
if (dir) { /* OEM code to Unicode */
|
||||
c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];
|
||||
|
||||
} else { /* Unicode to OEM code */
|
||||
for (c = 0; c < 0x80; c++) {
|
||||
if (chr == Tbl[c]) break;
|
||||
}
|
||||
c = (c + 0x80) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
|
||||
WCHAR ff_wtoupper ( /* Returns upper converted character */
|
||||
WCHAR chr /* Unicode character to be upper converted (BMP only) */
|
||||
)
|
||||
{
|
||||
/* Compressed upper conversion table */
|
||||
static const WCHAR cvt1[] = { /* U+0000 - U+0FFF */
|
||||
/* Basic Latin */
|
||||
0x0061,0x031A,
|
||||
/* Latin-1 Supplement */
|
||||
0x00E0,0x0317, 0x00F8,0x0307, 0x00FF,0x0001,0x0178,
|
||||
/* Latin Extended-A */
|
||||
0x0100,0x0130, 0x0132,0x0106, 0x0139,0x0110, 0x014A,0x012E, 0x0179,0x0106,
|
||||
/* Latin Extended-B */
|
||||
0x0180,0x004D,0x0243,0x0181,0x0182,0x0182,0x0184,0x0184,0x0186,0x0187,0x0187,0x0189,0x018A,0x018B,0x018B,0x018D,0x018E,0x018F,0x0190,0x0191,0x0191,0x0193,0x0194,0x01F6,0x0196,0x0197,0x0198,0x0198,0x023D,0x019B,0x019C,0x019D,0x0220,0x019F,0x01A0,0x01A0,0x01A2,0x01A2,0x01A4,0x01A4,0x01A6,0x01A7,0x01A7,0x01A9,0x01AA,0x01AB,0x01AC,0x01AC,0x01AE,0x01AF,0x01AF,0x01B1,0x01B2,0x01B3,0x01B3,0x01B5,0x01B5,0x01B7,0x01B8,0x01B8,0x01BA,0x01BB,0x01BC,0x01BC,0x01BE,0x01F7,0x01C0,0x01C1,0x01C2,0x01C3,0x01C4,0x01C5,0x01C4,0x01C7,0x01C8,0x01C7,0x01CA,0x01CB,0x01CA,
|
||||
0x01CD,0x0110, 0x01DD,0x0001,0x018E, 0x01DE,0x0112, 0x01F3,0x0003,0x01F1,0x01F4,0x01F4, 0x01F8,0x0128,
|
||||
0x0222,0x0112, 0x023A,0x0009,0x2C65,0x023B,0x023B,0x023D,0x2C66,0x023F,0x0240,0x0241,0x0241, 0x0246,0x010A,
|
||||
/* IPA Extensions */
|
||||
0x0253,0x0040,0x0181,0x0186,0x0255,0x0189,0x018A,0x0258,0x018F,0x025A,0x0190,0x025C,0x025D,0x025E,0x025F,0x0193,0x0261,0x0262,0x0194,0x0264,0x0265,0x0266,0x0267,0x0197,0x0196,0x026A,0x2C62,0x026C,0x026D,0x026E,0x019C,0x0270,0x0271,0x019D,0x0273,0x0274,0x019F,0x0276,0x0277,0x0278,0x0279,0x027A,0x027B,0x027C,0x2C64,0x027E,0x027F,0x01A6,0x0281,0x0282,0x01A9,0x0284,0x0285,0x0286,0x0287,0x01AE,0x0244,0x01B1,0x01B2,0x0245,0x028D,0x028E,0x028F,0x0290,0x0291,0x01B7,
|
||||
/* Greek, Coptic */
|
||||
0x037B,0x0003,0x03FD,0x03FE,0x03FF, 0x03AC,0x0004,0x0386,0x0388,0x0389,0x038A, 0x03B1,0x0311,
|
||||
0x03C2,0x0002,0x03A3,0x03A3, 0x03C4,0x0308, 0x03CC,0x0003,0x038C,0x038E,0x038F, 0x03D8,0x0118,
|
||||
0x03F2,0x000A,0x03F9,0x03F3,0x03F4,0x03F5,0x03F6,0x03F7,0x03F7,0x03F9,0x03FA,0x03FA,
|
||||
/* Cyrillic */
|
||||
0x0430,0x0320, 0x0450,0x0710, 0x0460,0x0122, 0x048A,0x0136, 0x04C1,0x010E, 0x04CF,0x0001,0x04C0, 0x04D0,0x0144,
|
||||
/* Armenian */
|
||||
0x0561,0x0426,
|
||||
|
||||
0x0000
|
||||
};
|
||||
static const WCHAR cvt2[] = { /* U+1000 - U+FFFF */
|
||||
/* Phonetic Extensions */
|
||||
0x1D7D,0x0001,0x2C63,
|
||||
/* Latin Extended Additional */
|
||||
0x1E00,0x0196, 0x1EA0,0x015A,
|
||||
/* Greek Extended */
|
||||
0x1F00,0x0608, 0x1F10,0x0606, 0x1F20,0x0608, 0x1F30,0x0608, 0x1F40,0x0606,
|
||||
0x1F51,0x0007,0x1F59,0x1F52,0x1F5B,0x1F54,0x1F5D,0x1F56,0x1F5F, 0x1F60,0x0608,
|
||||
0x1F70,0x000E,0x1FBA,0x1FBB,0x1FC8,0x1FC9,0x1FCA,0x1FCB,0x1FDA,0x1FDB,0x1FF8,0x1FF9,0x1FEA,0x1FEB,0x1FFA,0x1FFB,
|
||||
0x1F80,0x0608, 0x1F90,0x0608, 0x1FA0,0x0608, 0x1FB0,0x0004,0x1FB8,0x1FB9,0x1FB2,0x1FBC,
|
||||
0x1FCC,0x0001,0x1FC3, 0x1FD0,0x0602, 0x1FE0,0x0602, 0x1FE5,0x0001,0x1FEC, 0x1FF2,0x0001,0x1FFC,
|
||||
/* Letterlike Symbols */
|
||||
0x214E,0x0001,0x2132,
|
||||
/* Number forms */
|
||||
0x2170,0x0210, 0x2184,0x0001,0x2183,
|
||||
/* Enclosed Alphanumerics */
|
||||
0x24D0,0x051A, 0x2C30,0x042F,
|
||||
/* Latin Extended-C */
|
||||
0x2C60,0x0102, 0x2C67,0x0106, 0x2C75,0x0102,
|
||||
/* Coptic */
|
||||
0x2C80,0x0164,
|
||||
/* Georgian Supplement */
|
||||
0x2D00,0x0826,
|
||||
/* Full-width */
|
||||
0xFF41,0x031A,
|
||||
|
||||
0x0000
|
||||
};
|
||||
const WCHAR *p;
|
||||
WCHAR bc, nc, cmd;
|
||||
|
||||
|
||||
p = chr < 0x1000 ? cvt1 : cvt2;
|
||||
for (;;) {
|
||||
bc = *p++; /* Get block base */
|
||||
if (!bc || chr < bc) break;
|
||||
nc = *p++; cmd = nc >> 8; nc &= 0xFF; /* Get processing command and block size */
|
||||
if (chr < bc + nc) { /* In the block? */
|
||||
switch (cmd) {
|
||||
case 0: chr = p[chr - bc]; break; /* Table conversion */
|
||||
case 1: chr -= (chr - bc) & 1; break; /* Case pairs */
|
||||
case 2: chr -= 16; break; /* Shift -16 */
|
||||
case 3: chr -= 32; break; /* Shift -32 */
|
||||
case 4: chr -= 48; break; /* Shift -48 */
|
||||
case 5: chr -= 26; break; /* Shift -26 */
|
||||
case 6: chr += 8; break; /* Shift +8 */
|
||||
case 7: chr -= 80; break; /* Shift -80 */
|
||||
case 8: chr -= 0x1C60; break; /* Shift -0x1C60 */
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!cmd) p += nc;
|
||||
}
|
||||
|
||||
return chr;
|
||||
}
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Sample code of OS dependent controls for FatFs */
|
||||
/* (C)ChaN, 2014 */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include "../ff.h"
|
||||
|
||||
|
||||
#if _FS_REENTRANT
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Create a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to create a new
|
||||
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */
|
||||
BYTE vol, /* Corresponding logical drive being processed */
|
||||
_SYNC_t *sobj /* Pointer to return the created sync object */
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
*sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */
|
||||
ret = (int)(*sobj != INVALID_HANDLE_VALUE);
|
||||
|
||||
// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */
|
||||
// ret = 1; /* The initial value of the semaphore must be 1. */
|
||||
|
||||
// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */
|
||||
// ret = (int)(err == OS_NO_ERR);
|
||||
|
||||
// *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */
|
||||
// ret = (int)(*sobj != NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Delete a Synchronization Object */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called in f_mount() function to delete a synchronization
|
||||
/ object that created with ff_cre_syncobj function. When a 0 is returned,
|
||||
/ the f_mount() function fails with FR_INT_ERR.
|
||||
*/
|
||||
|
||||
int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */
|
||||
_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
||||
ret = CloseHandle(sobj); /* Win32 */
|
||||
|
||||
// ret = 1; /* uITRON (nothing to do) */
|
||||
|
||||
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */
|
||||
// ret = (int)(err == OS_NO_ERR);
|
||||
|
||||
// vSemaphoreDelete(sobj); /* FreeRTOS */
|
||||
// ret = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Request Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on entering file functions to lock the volume.
|
||||
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
|
||||
*/
|
||||
|
||||
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
|
||||
_SYNC_t sobj /* Sync object to wait */
|
||||
)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
|
||||
|
||||
// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */
|
||||
|
||||
// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */
|
||||
// ret = (int)(err == OS_NO_ERR);
|
||||
|
||||
// ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Release Grant to Access the Volume */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* This function is called on leaving file functions to unlock the volume.
|
||||
*/
|
||||
|
||||
void ff_rel_grant (
|
||||
_SYNC_t sobj /* Sync object to be signaled */
|
||||
)
|
||||
{
|
||||
ReleaseMutex(sobj); /* Win32 */
|
||||
|
||||
// sig_sem(sobj); /* uITRON */
|
||||
|
||||
// OSMutexPost(sobj); /* uC/OS-II */
|
||||
|
||||
// xSemaphoreGive(sobj); /* FreeRTOS */
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Allocate a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
|
||||
*/
|
||||
|
||||
void* ff_memalloc ( /* Returns pointer to the allocated memory block */
|
||||
UINT msize /* Number of bytes to allocate */
|
||||
)
|
||||
{
|
||||
return malloc(msize); /* Allocate a new memory block with POSIX API */
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------------*/
|
||||
/* Free a memory block */
|
||||
/*------------------------------------------------------------------------*/
|
||||
|
||||
void ff_memfree (
|
||||
void* mblock /* Pointer to the memory block to free */
|
||||
)
|
||||
{
|
||||
free(mblock); /* Discard the memory block with POSIX API */
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define u64 uint64_t
|
||||
|
||||
#define vu8 volatile u8
|
||||
#define vu16 volatile u16
|
||||
#define vu32 volatile u32
|
||||
#define vu64 volatile u64
|
||||
@@ -1,9 +1,5 @@
|
||||
// Copyright 2014 Normmatt
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "../../types.h"
|
||||
|
||||
void ioDelay(u32 us);
|
||||
void waitcycles(u32 us);
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
.text
|
||||
.arm
|
||||
.global waitcycles
|
||||
.type waitcycles STT_FUNC
|
||||
.align 4
|
||||
|
||||
@waitcycles ( u32 us )
|
||||
.global waitcycles
|
||||
.type waitcycles, %function
|
||||
waitcycles:
|
||||
PUSH {R0-R2,LR}
|
||||
STR R0, [SP,#4]
|
||||
waitcycles_loop:
|
||||
LDR R3, [SP,#4]
|
||||
SUBS R2, R3, #1
|
||||
STR R2, [SP,#4]
|
||||
CMP R3, #0
|
||||
BNE waitcycles_loop
|
||||
POP {R0-R2,PC}
|
||||
push {r0-r2, lr}
|
||||
str r0, [sp, #4]
|
||||
waitcycles_loop:
|
||||
ldr r3, [sp, #4]
|
||||
subs r2, r3, #1
|
||||
str r2, [sp, #4]
|
||||
cmp r3, #0
|
||||
bne waitcycles_loop
|
||||
pop {r0-r2, pc}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +1,48 @@
|
||||
#ifndef __SDMMC_H__
|
||||
#define __SDMMC_H__
|
||||
#pragma once
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#include "../../types.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#define SDMMC_BASE 0x10006000
|
||||
|
||||
#define SDMMC_BASE 0x10006000
|
||||
#define REG_SDCMD 0x00
|
||||
#define REG_SDPORTSEL 0x02
|
||||
#define REG_SDCMDARG 0x04
|
||||
#define REG_SDCMDARG0 0x04
|
||||
#define REG_SDCMDARG1 0x06
|
||||
#define REG_SDSTOP 0x08
|
||||
#define REG_SDBLKCOUNT 0x0A
|
||||
|
||||
#define REG_SDCMD 0x00
|
||||
#define REG_SDPORTSEL 0x02
|
||||
#define REG_SDCMDARG 0x04
|
||||
#define REG_SDCMDARG0 0x04
|
||||
#define REG_SDCMDARG1 0x06
|
||||
#define REG_SDSTOP 0x08
|
||||
#define REG_SDBLKCOUNT 0x0a
|
||||
#define REG_SDRESP0 0x0C
|
||||
#define REG_SDRESP1 0x0E
|
||||
#define REG_SDRESP2 0x10
|
||||
#define REG_SDRESP3 0x12
|
||||
#define REG_SDRESP4 0x14
|
||||
#define REG_SDRESP5 0x16
|
||||
#define REG_SDRESP6 0x18
|
||||
#define REG_SDRESP7 0x1A
|
||||
|
||||
#define REG_SDRESP0 0x0c
|
||||
#define REG_SDRESP1 0x0e
|
||||
#define REG_SDRESP2 0x10
|
||||
#define REG_SDRESP3 0x12
|
||||
#define REG_SDRESP4 0x14
|
||||
#define REG_SDRESP5 0x16
|
||||
#define REG_SDRESP6 0x18
|
||||
#define REG_SDRESP7 0x1a
|
||||
#define REG_SDSTATUS0 0x1C
|
||||
#define REG_SDSTATUS1 0x1E
|
||||
|
||||
#define REG_SDSTATUS0 0x1c
|
||||
#define REG_SDSTATUS1 0x1e
|
||||
#define REG_SDIRMASK0 0x20
|
||||
#define REG_SDIRMASK1 0x22
|
||||
#define REG_SDCLKCTL 0x24
|
||||
|
||||
#define REG_SDIRMASK0 0x20
|
||||
#define REG_SDIRMASK1 0x22
|
||||
#define REG_SDCLKCTL 0x24
|
||||
|
||||
#define REG_SDBLKLEN 0x26
|
||||
#define REG_SDOPT 0x28
|
||||
#define REG_SDFIFO 0x30
|
||||
#define REG_SDBLKLEN 0x26
|
||||
#define REG_SDOPT 0x28
|
||||
#define REG_SDFIFO 0x30
|
||||
|
||||
#define REG_DATACTL 0xd8
|
||||
#define REG_SDRESET 0xe0
|
||||
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
|
||||
#define REG_DATACTL 0xD8
|
||||
#define REG_SDRESET 0xE0
|
||||
#define REG_SDPROTECTED 0xF6 //bit 0 determines if sd is protected or not?
|
||||
|
||||
#define REG_DATACTL32 0x100
|
||||
#define REG_SDBLKLEN32 0x104
|
||||
#define REG_SDBLKCOUNT32 0x108
|
||||
#define REG_SDFIFO32 0x10C
|
||||
#define REG_DATACTL32 0x100
|
||||
#define REG_SDBLKLEN32 0x104
|
||||
#define REG_SDBLKCOUNT32 0x108
|
||||
#define REG_SDFIFO32 0x10C
|
||||
|
||||
#define REG_CLK_AND_WAIT_CTL 0x138
|
||||
#define REG_RESET_SDIO 0x1e0
|
||||
#define REG_RESET_SDIO 0x1E0
|
||||
|
||||
#define TMIO_STAT0_CMDRESPEND 0x0001
|
||||
#define TMIO_STAT0_DATAEND 0x0004
|
||||
@@ -70,115 +66,35 @@
|
||||
#define TMIO_STAT1_CMD_BUSY 0x4000
|
||||
#define TMIO_STAT1_ILL_ACCESS 0x8000
|
||||
|
||||
//Comes from TWLSDK mongoose.tef DWARF info
|
||||
#define SDMC_NORMAL 0x00000000
|
||||
#define SDMC_ERR_COMMAND 0x00000001
|
||||
#define SDMC_ERR_CRC 0x00000002
|
||||
#define SDMC_ERR_END 0x00000004
|
||||
#define SDMC_ERR_TIMEOUT 0x00000008
|
||||
#define SDMC_ERR_FIFO_OVF 0x00000010
|
||||
#define SDMC_ERR_FIFO_UDF 0x00000020
|
||||
#define SDMC_ERR_WP 0x00000040
|
||||
#define SDMC_ERR_ABORT 0x00000080
|
||||
#define SDMC_ERR_FPGA_TIMEOUT 0x00000100
|
||||
#define SDMC_ERR_PARAM 0x00000200
|
||||
#define SDMC_ERR_R1_STATUS 0x00000800
|
||||
#define SDMC_ERR_NUM_WR_SECTORS 0x00001000
|
||||
#define SDMC_ERR_RESET 0x00002000
|
||||
#define SDMC_ERR_ILA 0x00004000
|
||||
#define SDMC_ERR_INFO_DETECT 0x00008000
|
||||
|
||||
#define SDMC_STAT_ERR_UNKNOWN 0x00080000
|
||||
#define SDMC_STAT_ERR_CC 0x00100000
|
||||
#define SDMC_STAT_ERR_ECC_FAILED 0x00200000
|
||||
#define SDMC_STAT_ERR_CRC 0x00800000
|
||||
#define SDMC_STAT_ERR_OTHER 0xf9c70008
|
||||
|
||||
#define TMIO_MASK_ALL 0x837f031d
|
||||
#define TMIO_MASK_ALL 0x837F031D
|
||||
|
||||
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
|
||||
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
||||
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
|
||||
|
||||
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
|
||||
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef struct mmcdevice {
|
||||
u8 *rData;
|
||||
const u8 *tData;
|
||||
u32 size;
|
||||
u32 error;
|
||||
u16 stat0;
|
||||
u16 stat1;
|
||||
u32 ret[4];
|
||||
u32 initarg;
|
||||
u32 isSDHC;
|
||||
u32 clk;
|
||||
u32 SDOPT;
|
||||
u32 devicenumber;
|
||||
u32 total_size; //size in sectors of the device
|
||||
u32 res;
|
||||
} mmcdevice;
|
||||
|
||||
typedef struct mmcdevice {
|
||||
uint8_t* data;
|
||||
uint32_t size;
|
||||
uint32_t error;
|
||||
uint16_t stat0;
|
||||
uint16_t stat1;
|
||||
uint32_t ret[4];
|
||||
uint32_t initarg;
|
||||
uint32_t isSDHC;
|
||||
uint32_t clk;
|
||||
uint32_t SDOPT;
|
||||
uint32_t devicenumber;
|
||||
uint32_t total_size; //size in sectors of the device
|
||||
uint32_t res;
|
||||
} mmcdevice;
|
||||
|
||||
void sdmmc_sdcard_init();
|
||||
int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out);
|
||||
int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
|
||||
int sdmmc_sdcard_writesector(uint32_t sector_no, uint8_t *in);
|
||||
int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
|
||||
|
||||
int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
|
||||
int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
|
||||
|
||||
mmcdevice *getMMCDevice(int drive);
|
||||
|
||||
void InitSD();
|
||||
int Nand_Init();
|
||||
int SD_Init();
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline uint16_t sdmmc_read16(uint16_t reg) {
|
||||
//---------------------------------------------------------------------------------
|
||||
return *(volatile uint16_t*)(SDMMC_BASE + reg);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline void sdmmc_write16(uint16_t reg, uint16_t val) {
|
||||
//---------------------------------------------------------------------------------
|
||||
*(volatile uint16_t*)(SDMMC_BASE + reg) = val;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline uint32_t sdmmc_read32(uint16_t reg) {
|
||||
//---------------------------------------------------------------------------------
|
||||
return *(volatile uint32_t*)(SDMMC_BASE + reg);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline void sdmmc_write32(uint16_t reg, uint32_t val) {
|
||||
//---------------------------------------------------------------------------------
|
||||
*(volatile uint32_t*)(SDMMC_BASE + reg) = val;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) {
|
||||
//---------------------------------------------------------------------------------
|
||||
uint16_t val = sdmmc_read16(reg);
|
||||
val &= ~clear;
|
||||
val |= set;
|
||||
sdmmc_write16(reg, val);
|
||||
}
|
||||
|
||||
static inline void setckl(uint32_t data)
|
||||
{
|
||||
sdmmc_mask16(REG_SDCLKCTL,0x100,0);
|
||||
sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF);
|
||||
sdmmc_mask16(REG_SDCLKCTL,0x0,0x100);
|
||||
}
|
||||
|
||||
#endif
|
||||
u32 sdmmc_sdcard_init();
|
||||
int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||
int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
|
||||
int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
|
||||
int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
|
||||
void sdmmc_get_cid(bool isNand, u32 *info);
|
||||
mmcdevice *getMMCDevice(int drive);
|
||||
602
source/firm.c
602
source/firm.c
@@ -1,221 +1,467 @@
|
||||
/*
|
||||
* firm.c
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "firm.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "fs.h"
|
||||
#include "exceptions.h"
|
||||
#include "patches.h"
|
||||
#include "memory.h"
|
||||
#include "fs.h"
|
||||
#include "strings.h"
|
||||
#include "cache.h"
|
||||
#include "emunand.h"
|
||||
#include "crypto.h"
|
||||
#include "draw.h"
|
||||
#include "screen.h"
|
||||
#include "fmt.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
firmHeader *firmLocation = (firmHeader *)0x24000000;
|
||||
firmSectionHeader *section;
|
||||
u32 firmSize = 0;
|
||||
u8 mode = 1,
|
||||
console = 1,
|
||||
emuNAND = 0,
|
||||
a9lhSetup = 0,
|
||||
updatedSys = 0,
|
||||
usePatchedFirm = 0;
|
||||
u16 pressed;
|
||||
char *firmPathPatched = NULL;
|
||||
static inline bool loadFirmFromStorage(FirmwareType firmType)
|
||||
{
|
||||
const char *firmwareFiles[] = {
|
||||
"native.firm",
|
||||
"twl.firm",
|
||||
"agb.firm",
|
||||
"safe.firm",
|
||||
"sysupdater.firm"
|
||||
},
|
||||
*cetkFiles[] = {
|
||||
"cetk",
|
||||
"cetk_twl",
|
||||
"cetk_agb",
|
||||
"cetk_safe",
|
||||
"cetk_sysupdater"
|
||||
};
|
||||
|
||||
void setupCFW(void){
|
||||
u32 firmSize = fileRead(firm, firmType == NATIVE_FIRM1X2X ? firmwareFiles[0] : firmwareFiles[(u32)firmType], 0x400000 + sizeof(Cxi) + 0x200);
|
||||
|
||||
//Detect the console being used
|
||||
if(PDN_MPCORE_CFG == 1) console = 0;
|
||||
if(!firmSize) return false;
|
||||
|
||||
//Get pressed buttons
|
||||
pressed = HID_PAD;
|
||||
if(firmSize <= sizeof(Cxi) + 0x200) error("The FIRM in /luma is not valid.");
|
||||
|
||||
//Determine if A9LH is installed via PDN_SPI_CNT and an user flag
|
||||
if((*((u8*)0x101401C0) == 0x0) || fileExists("/rei/installeda9lh")){
|
||||
a9lhSetup = 1;
|
||||
//Check flag for > 9.2 SysNAND
|
||||
if(fileExists("/rei/updatedsysnand")) updatedSys = 1;
|
||||
if(memcmp(firm, "FIRM", 4) != 0)
|
||||
{
|
||||
u8 cetk[0xA50];
|
||||
|
||||
if(fileRead(cetk, firmType == NATIVE_FIRM1X2X ? cetkFiles[0] : cetkFiles[(u32)firmType], sizeof(cetk)) != sizeof(cetk) ||
|
||||
!decryptNusFirm((Ticket *)(cetk + 0x140), (Cxi *)firm, firmSize))
|
||||
error("The FIRM in /luma is encrypted or corrupted.");
|
||||
}
|
||||
|
||||
/* If L is pressed, and on an updated SysNAND setup the SAFE MODE combo
|
||||
is not pressed, boot 9.0 FIRM */
|
||||
if((pressed & BUTTON_L1) && !(updatedSys && pressed == SAFEMODE)) mode = 0;
|
||||
//Check that the FIRM is right for the console from the ARM9 section address
|
||||
if((firm->section[3].offset != 0 ? firm->section[3].address : firm->section[2].address) != (ISN3DS ? (u8 *)0x8006000 : (u8 *)0x8006800))
|
||||
error("The FIRM in /luma is not for this console.");
|
||||
|
||||
/* If L or R aren't pressed on a 9.0/9.2 SysNAND, or the 9.0 FIRM is selected
|
||||
or R is pressed on a > 9.2 SysNAND, boot emuNAND */
|
||||
if((updatedSys && (!mode || ((pressed & BUTTON_R1) && pressed != SAFEMODE))) ||
|
||||
(!updatedSys && mode && !(pressed & BUTTON_R1))) emuNAND = 1;
|
||||
|
||||
if(mode) firmPathPatched = emuNAND ? "/rei/patched_firmware_emu.bin" :
|
||||
"/rei/patched_firmware_sys.bin";
|
||||
|
||||
//Skip decrypting and patching FIRM
|
||||
if(fileExists("/rei/usepatchedfw")){
|
||||
//Only needed with this flag
|
||||
if(!mode) firmPathPatched = "/rei/patched_firmware90.bin";
|
||||
if (fileExists(firmPathPatched)) usePatchedFirm = 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//Load firm into FCRAM
|
||||
u8 loadFirm(void){
|
||||
static inline void mergeSection0(FirmwareType firmType, bool loadFromStorage)
|
||||
{
|
||||
u32 srcModuleSize;
|
||||
const char *extModuleSizeError = "The external FIRM modules are too large.";
|
||||
|
||||
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
|
||||
if(!usePatchedFirm && !a9lhSetup && !mode){
|
||||
//Read FIRM from NAND and write to FCRAM
|
||||
firmSize = console ? 0xF2000 : 0xE9000;
|
||||
nandFirm0((u8*)firmLocation, firmSize, console);
|
||||
//Check for correct decryption
|
||||
if(memcmp((u8*)firmLocation, "FIRM", 4) != 0) return 1;
|
||||
}
|
||||
//Load FIRM from SD
|
||||
else{
|
||||
char *path = usePatchedFirm ? firmPathPatched :
|
||||
(mode ? "/rei/firmware.bin" : "/rei/firmware90.bin");
|
||||
firmSize = fileSize(path);
|
||||
if (!firmSize) return 1;
|
||||
fileRead((u8*)firmLocation, path, firmSize);
|
||||
u32 nbModules = 0,
|
||||
isCustomModule = false;
|
||||
struct
|
||||
{
|
||||
char name[8];
|
||||
u8 *src;
|
||||
u32 size;
|
||||
} moduleList[6];
|
||||
|
||||
//1) Parse info concerning Nintendo's modules
|
||||
for(u8 *src = (u8 *)firm + firm->section[0].offset, *srcEnd = src + firm->section[0].size; src < srcEnd; src += srcModuleSize, nbModules++)
|
||||
{
|
||||
memcpy(moduleList[nbModules].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
|
||||
moduleList[nbModules].src = src;
|
||||
srcModuleSize = moduleList[nbModules].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
}
|
||||
|
||||
section = firmLocation->section;
|
||||
if(firmType == NATIVE_FIRM)
|
||||
{
|
||||
//2) Merge that info with our own modules'
|
||||
for(u8 *src = (u8 *)0x1FF60000; src < (u8 *)(0x1FF60000 + LUMA_SECTION0_SIZE); src += srcModuleSize)
|
||||
{
|
||||
const char *name = ((Cxi *)src)->exHeader.systemControlInfo.appTitle;
|
||||
|
||||
//Check that the loaded FIRM matches the console
|
||||
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) return 1;
|
||||
u32 i;
|
||||
for(i = 0; i < nbModules && memcmp(name, moduleList[i].name, 8) != 0; i++);
|
||||
|
||||
if(console && !usePatchedFirm)
|
||||
decArm9Bin((u8*)firmLocation + section[2].offset, mode);
|
||||
if(i == nbModules) isCustomModule = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
memcpy(moduleList[i].name, ((Cxi *)src)->exHeader.systemControlInfo.appTitle, 8);
|
||||
moduleList[i].src = src;
|
||||
srcModuleSize = moduleList[i].size = ((Cxi *)src)->ncch.contentSize * 0x200;
|
||||
}
|
||||
|
||||
//Nand redirection
|
||||
u8 loadEmu(void){
|
||||
|
||||
u32 emuOffset = 0,
|
||||
emuHeader = 0,
|
||||
emuRead = 0,
|
||||
emuWrite = 0,
|
||||
sdmmcOffset = 0,
|
||||
mpuOffset = 0,
|
||||
emuCodeOffset = 0;
|
||||
|
||||
//Read emunand code from SD
|
||||
char path[] = "/rei/emunand/emunand.bin";
|
||||
u32 size = fileSize(path);
|
||||
if (!size) return 1;
|
||||
if(!console || !mode) nandRedir[5] = 0xA4;
|
||||
//Find offset for emuNAND code from the offset in nandRedir
|
||||
u8 *emuCodeTmp = &nandRedir[4];
|
||||
emuCodeOffset = *(u32*)emuCodeTmp - (u32)section[2].address +
|
||||
section[2].offset + (u32)firmLocation;
|
||||
fileRead((u8*)emuCodeOffset, path, size);
|
||||
|
||||
//Find and patch emunand related offsets
|
||||
u32 *pos_sdmmc = memsearch((u32*)emuCodeOffset, "SDMC", size, 4);
|
||||
u32 *pos_offset = memsearch((u32*)emuCodeOffset, "NAND", size, 4);
|
||||
u32 *pos_header = memsearch((u32*)emuCodeOffset, "NCSD", size, 4);
|
||||
getSDMMC(firmLocation, &sdmmcOffset, firmSize);
|
||||
getEmunandSect(&emuOffset, &emuHeader);
|
||||
getEmuRW(firmLocation, firmSize, &emuRead, &emuWrite);
|
||||
getMPU(firmLocation, &mpuOffset, firmSize);
|
||||
*pos_sdmmc = sdmmcOffset;
|
||||
*pos_offset = emuOffset;
|
||||
*pos_header = emuHeader;
|
||||
|
||||
//Patch emuNAND code in memory for O3DS and 9.0 N3DS
|
||||
if(!console || !mode){
|
||||
u32 *pos_instr = memsearch((u32*)emuCodeOffset, "\xA6\x01\x08\x30", size, 4);
|
||||
memcpy((u8*)pos_instr, emuInstr, sizeof(emuInstr));
|
||||
if(isCustomModule) nbModules++;
|
||||
}
|
||||
|
||||
//Add emunand hooks
|
||||
memcpy((u8*)emuRead, nandRedir, sizeof(nandRedir));
|
||||
memcpy((u8*)emuWrite, nandRedir, sizeof(nandRedir));
|
||||
//3) Read or copy the modules
|
||||
u8 *dst = firm->section[0].address;
|
||||
for(u32 i = 0, dstModuleSize; i < nbModules; i++)
|
||||
{
|
||||
dstModuleSize = 0;
|
||||
|
||||
//Set MPU for emu code region
|
||||
memcpy((u8*)mpuOffset, mpu, sizeof(mpu));
|
||||
if(loadFromStorage)
|
||||
{
|
||||
char fileName[24];
|
||||
|
||||
return 0;
|
||||
}
|
||||
//Read modules from files if they exist
|
||||
sprintf(fileName, "sysmodules/%.8s.cxi", moduleList[i].name);
|
||||
|
||||
//Patches
|
||||
u8 patchFirm(void){
|
||||
if(usePatchedFirm) return 0;
|
||||
dstModuleSize = getFileSize(fileName);
|
||||
|
||||
if(emuNAND){
|
||||
if (loadEmu()) return 1;
|
||||
}
|
||||
else if (a9lhSetup){
|
||||
//Patch FIRM partitions writes on SysNAND to protect A9LH
|
||||
u32 writeOffset = 0;
|
||||
getFIRMWrite(firmLocation, firmSize, &writeOffset);
|
||||
memcpy((u8*)writeOffset, FIRMblock, sizeof(FIRMblock));
|
||||
}
|
||||
if(dstModuleSize != 0)
|
||||
{
|
||||
if(dstModuleSize > 0x60000) error(extModuleSizeError);
|
||||
|
||||
//Disable signature checks
|
||||
u32 sigOffset = 0,
|
||||
sigOffset2 = 0;
|
||||
if(dstModuleSize <= sizeof(Cxi) + 0x200 ||
|
||||
fileRead(dst, fileName, dstModuleSize) != dstModuleSize ||
|
||||
memcmp(((Cxi *)dst)->ncch.magic, "NCCH", 4) != 0 ||
|
||||
memcmp(moduleList[i].name, ((Cxi *)dst)->exHeader.systemControlInfo.appTitle, sizeof(((Cxi *)dst)->exHeader.systemControlInfo.appTitle)) != 0)
|
||||
error("An external FIRM module is invalid or corrupted.");
|
||||
|
||||
getSignatures(firmLocation, firmSize, &sigOffset, &sigOffset2);
|
||||
memcpy((u8*)sigOffset, sigPat1, sizeof(sigPat1));
|
||||
memcpy((u8*)sigOffset2, sigPat2, sizeof(sigPat2));
|
||||
dst += dstModuleSize;
|
||||
}
|
||||
}
|
||||
|
||||
//Patch ARM9 entrypoint on N3DS to skip arm9loader
|
||||
if(console){
|
||||
u32 *arm9 = (u32*)&firmLocation->arm9Entry;
|
||||
*arm9 = 0x801B01C;
|
||||
}
|
||||
|
||||
if(mode){
|
||||
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
|
||||
u32 rebootOffset = 0,
|
||||
fOpenOffset = 0;
|
||||
|
||||
//Read reboot code from SD
|
||||
char *path = "/rei/reboot/reboot.bin";
|
||||
u32 size = fileSize(path);
|
||||
if (!size) return 1;
|
||||
getReboot(firmLocation, firmSize, &rebootOffset);
|
||||
fileRead((u8*)rebootOffset, path, size);
|
||||
|
||||
//Calculate the fOpen offset and put it in the right location
|
||||
u32 *pos_fopen = memsearch((u32*)rebootOffset, "OPEN", size, 4);
|
||||
getfOpen(firmLocation, firmSize, &fOpenOffset);
|
||||
*pos_fopen = fOpenOffset;
|
||||
|
||||
//Patch path for emuNAND-patched FIRM
|
||||
if(emuNAND){
|
||||
u32 *pos_path = memsearch((u32*)rebootOffset, L"sys", size, 6);
|
||||
memcpy((u8*)pos_path, L"emu", 6);
|
||||
if(!dstModuleSize)
|
||||
{
|
||||
memcpy(dst, moduleList[i].src, moduleList[i].size);
|
||||
dst += moduleList[i].size;
|
||||
}
|
||||
}
|
||||
|
||||
//Write patched FIRM to SD if needed
|
||||
if(firmPathPatched)
|
||||
if(fileWrite((u8*)firmLocation, firmPathPatched, firmSize) != 0) return 1;
|
||||
|
||||
return 0;
|
||||
//4) Patch NATIVE_FIRM if necessary
|
||||
if(isCustomModule)
|
||||
{
|
||||
if(patchK11ModuleLoading(firm->section[0].size, dst - firm->section[0].address, (u8 *)firm + firm->section[1].offset, firm->section[1].size) != 0)
|
||||
error("Failed to inject custom sysmodule");
|
||||
}
|
||||
}
|
||||
|
||||
void launchFirm(void){
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode)
|
||||
{
|
||||
//Load FIRM from CTRNAND
|
||||
u32 firmVersion = firmRead(firm, (u32)*firmType);
|
||||
|
||||
if(console && mode) setKeyXs((u8*)firmLocation + section[2].offset);
|
||||
if(firmVersion == 0xFFFFFFFF) error("Failed to get the CTRNAND FIRM.");
|
||||
|
||||
//Copy firm partitions to respective memory locations
|
||||
memcpy(section[0].address, (u8*)firmLocation + section[0].offset, section[0].size);
|
||||
memcpy(section[1].address, (u8*)firmLocation + section[1].offset, section[1].size);
|
||||
memcpy(section[2].address, (u8*)firmLocation + section[2].offset, section[2].size);
|
||||
bool mustLoadFromStorage = false;
|
||||
|
||||
//Run ARM11 screen stuff
|
||||
vu32 *arm11 = (vu32*)0x1FFFFFF8;
|
||||
*arm11 = (u32)shutdownLCD;
|
||||
while (*arm11);
|
||||
if(!ISN3DS && *firmType == NATIVE_FIRM && !ISDEVUNIT)
|
||||
{
|
||||
if(firmVersion < 0x18)
|
||||
{
|
||||
//We can't boot < 3.x EmuNANDs
|
||||
if(nandType != FIRMWARE_SYSNAND)
|
||||
error("An old unsupported EmuNAND has been detected.\nLuma3DS is unable to boot it.");
|
||||
|
||||
if(isSafeMode) error("SAFE_MODE is not supported on 1.x/2.x FIRM.");
|
||||
|
||||
*firmType = NATIVE_FIRM1X2X;
|
||||
}
|
||||
|
||||
//We can't boot a 3.x/4.x NATIVE_FIRM, load one from SD/CTRNAND
|
||||
else if(firmVersion < 0x25) mustLoadFromStorage = true;
|
||||
}
|
||||
|
||||
if((loadFromStorage || mustLoadFromStorage) && loadFirmFromStorage(*firmType)) firmVersion = 0xFFFFFFFF;
|
||||
else
|
||||
{
|
||||
if(mustLoadFromStorage) error("An old unsupported FIRM has been detected.\nCopy a firmware.bin in /luma to boot.");
|
||||
if(!decryptExeFs((Cxi *)firm)) error("The CTRNAND FIRM is corrupted.");
|
||||
if(ISDEVUNIT) firmVersion = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset,
|
||||
*arm11Section1 = (u8 *)firm + firm->section[1].offset;
|
||||
|
||||
if(ISN3DS)
|
||||
{
|
||||
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
|
||||
kernel9Loader((Arm9Bin *)arm9Section);
|
||||
firm->arm9Entry = (u8 *)0x801B01C;
|
||||
}
|
||||
|
||||
//Set ARM11 kernel
|
||||
*arm11 = (u32)firmLocation->arm11Entry;
|
||||
|
||||
//Final jump to arm9 binary
|
||||
((void (*)())firmLocation->arm9Entry)();
|
||||
}
|
||||
//Find the Process9 .code location, size and memory address
|
||||
u32 process9Size,
|
||||
process9MemAddr;
|
||||
u8 *process9Offset = getProcess9Info(arm9Section, firm->section[2].size, &process9Size, &process9MemAddr);
|
||||
|
||||
//Find the Kernel11 SVC table and handler, exceptions page and free space locations
|
||||
u32 baseK11VA;
|
||||
u8 *freeK11Space;
|
||||
u32 *arm11SvcHandler,
|
||||
*arm11ExceptionsPage,
|
||||
*arm11SvcTable = getKernel11Info(arm11Section1, firm->section[1].size, &baseK11VA, &freeK11Space, &arm11SvcHandler, &arm11ExceptionsPage);
|
||||
|
||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
||||
ret = 0;
|
||||
|
||||
installMMUHook(arm11Section1, firm->section[1].size, &freeK11Space);
|
||||
installK11MainHook(arm11Section1, firm->section[1].size, isSafeMode, baseK11VA, arm11SvcTable, arm11ExceptionsPage, &freeK11Space);
|
||||
installSvcConnectToPortInitHook(arm11SvcTable, arm11ExceptionsPage, &freeK11Space);
|
||||
installSvcCustomBackdoor(arm11SvcTable, &freeK11Space, arm11ExceptionsPage);
|
||||
|
||||
//Apply signature patches
|
||||
ret += patchSignatureChecks(process9Offset, process9Size);
|
||||
|
||||
//Apply EmuNAND patches
|
||||
if(nandType != FIRMWARE_SYSNAND) ret += patchEmuNand(arm9Section, kernel9Size, process9Offset, process9Size, firm->section[2].address);
|
||||
|
||||
//Apply FIRM0/1 writes patches on SysNAND to protect A9LH
|
||||
else ret += patchFirmWrites(process9Offset, process9Size);
|
||||
|
||||
//Apply firmlaunch patches
|
||||
ret += patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
|
||||
|
||||
//Apply dev unit check patches related to NCCH encryption
|
||||
if(!ISDEVUNIT)
|
||||
{
|
||||
ret += patchZeroKeyNcchEncryptionCheck(process9Offset, process9Size);
|
||||
ret += patchNandNcchEncryptionCheck(process9Offset, process9Size);
|
||||
}
|
||||
|
||||
//11.0 FIRM patches
|
||||
if(firmVersion >= (ISN3DS ? 0x21 : 0x52))
|
||||
{
|
||||
//Apply anti-anti-DG patches
|
||||
ret += patchTitleInstallMinVersionChecks(process9Offset, process9Size, firmVersion);
|
||||
}
|
||||
|
||||
//Apply UNITINFO patches
|
||||
if(doUnitinfoPatch)
|
||||
{
|
||||
ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
if(!ISDEVUNIT) ret += patchCheckForDevCommonKey(process9Offset, process9Size);
|
||||
}
|
||||
|
||||
if(enableExceptionHandlers)
|
||||
{
|
||||
//ARM9 exception handlers
|
||||
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
|
||||
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
|
||||
ret += patchKernel9Panic(arm9Section, kernel9Size);
|
||||
}
|
||||
|
||||
if(CONFIG(PATCHACCESS))
|
||||
ret += patchP9AccessChecks(process9Offset, process9Size);
|
||||
|
||||
mergeSection0(NATIVE_FIRM, loadFromStorage);
|
||||
firm->section[0].size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||
|
||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
|
||||
if(ISN3DS)
|
||||
{
|
||||
kernel9Loader((Arm9Bin *)arm9Section);
|
||||
firm->arm9Entry = (u8 *)0x801301C;
|
||||
}
|
||||
|
||||
//Find the Process9 .code location, size and memory address
|
||||
u32 process9Size,
|
||||
process9MemAddr;
|
||||
u8 *process9Offset = getProcess9Info(arm9Section, firm->section[3].size, &process9Size, &process9MemAddr);
|
||||
|
||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
||||
ret = 0;
|
||||
|
||||
ret += patchLgySignatureChecks(process9Offset, process9Size);
|
||||
ret += patchTwlInvalidSignatureChecks(process9Offset, process9Size);
|
||||
ret += patchTwlNintendoLogoChecks(process9Offset, process9Size);
|
||||
ret += patchTwlWhitelistChecks(process9Offset, process9Size);
|
||||
if(ISN3DS || firmVersion > 0x11) ret += patchTwlFlashcartChecks(process9Offset, process9Size, firmVersion);
|
||||
else if(!ISN3DS && firmVersion == 0x11) ret += patchOldTwlFlashcartChecks(process9Offset, process9Size);
|
||||
ret += patchTwlShaHashChecks(process9Offset, process9Size);
|
||||
|
||||
//Apply UNITINFO patch
|
||||
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
mergeSection0(TWL_FIRM, true);
|
||||
firm->section[0].size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[3].offset;
|
||||
|
||||
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
|
||||
if(ISN3DS)
|
||||
{
|
||||
kernel9Loader((Arm9Bin *)arm9Section);
|
||||
firm->arm9Entry = (u8 *)0x801301C;
|
||||
}
|
||||
|
||||
//Find the Process9 .code location, size and memory address
|
||||
u32 process9Size,
|
||||
process9MemAddr;
|
||||
u8 *process9Offset = getProcess9Info(arm9Section, firm->section[3].size, &process9Size, &process9MemAddr);
|
||||
|
||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
||||
ret = 0;
|
||||
|
||||
ret += patchLgySignatureChecks(process9Offset, process9Size);
|
||||
if(CONFIG(SHOWGBABOOT)) ret += patchAgbBootSplash(process9Offset, process9Size);
|
||||
|
||||
//Apply UNITINFO patch
|
||||
if(doUnitinfoPatch) ret += patchUnitInfoValueSet(arm9Section, kernel9Size);
|
||||
|
||||
if(loadFromStorage)
|
||||
{
|
||||
mergeSection0(AGB_FIRM, true);
|
||||
firm->section[0].size = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers)
|
||||
{
|
||||
u8 *arm9Section = (u8 *)firm + firm->section[2].offset;
|
||||
|
||||
if(ISN3DS)
|
||||
{
|
||||
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip kernel9loader
|
||||
kernel9Loader((Arm9Bin *)arm9Section);
|
||||
firm->arm9Entry = (u8 *)0x801B01C;
|
||||
}
|
||||
|
||||
//Find the Process9 .code location, size and memory address
|
||||
u32 process9Size,
|
||||
process9MemAddr;
|
||||
u8 *process9Offset = getProcess9Info(arm9Section, firm->section[2].size, &process9Size, &process9MemAddr);
|
||||
|
||||
u32 kernel9Size = (u32)(process9Offset - arm9Section) - sizeof(Cxi) - 0x200,
|
||||
ret = 0;
|
||||
|
||||
ret += ISN3DS ? patchFirmWrites(process9Offset, process9Size) : patchOldFirmWrites(process9Offset, process9Size);
|
||||
|
||||
ret += ISN3DS ? patchSignatureChecks(process9Offset, process9Size) : patchOldSignatureChecks(process9Offset, process9Size);
|
||||
|
||||
if(enableExceptionHandlers)
|
||||
{
|
||||
//ARM9 exception handlers
|
||||
ret += patchArm9ExceptionHandlersInstall(arm9Section, kernel9Size);
|
||||
ret += patchSvcBreak9(arm9Section, kernel9Size, (u32)firm->section[2].address);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) bool overlaps(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
if(as <= bs && bs <= ae)
|
||||
return true;
|
||||
if(bs <= as && as <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static __attribute__((noinline)) bool inRange(u32 as, u32 ae, u32 bs, u32 be)
|
||||
{
|
||||
if(as >= bs && ae <= be)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool checkFirmPayload(u32 payloadSize)
|
||||
{
|
||||
if(memcmp(firm->magic, "FIRM", 4) != 0 || firm->arm9Entry == NULL) //Allow for the ARM11 entrypoint to be zero in which case nothing is done on the ARM11 side
|
||||
return false;
|
||||
|
||||
bool arm9EpFound = false,
|
||||
arm11EpFound = false;
|
||||
|
||||
u32 size = 0x200;
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
size += firm->section[i].size;
|
||||
|
||||
if(size != payloadSize) return false;
|
||||
|
||||
for(u32 i = 0; i < 4; i++)
|
||||
{
|
||||
FirmSection *section = &firm->section[i];
|
||||
|
||||
//Allow empty sections
|
||||
if(section->size == 0)
|
||||
continue;
|
||||
|
||||
if((section->offset < 0x200) ||
|
||||
(section->address + section->size < section->address) || //Overflow check
|
||||
((u32)section->address & 3) || (section->offset & 0x1FF) || (section->size & 0x1FF) || //Alignment check
|
||||
(overlaps((u32)section->address, (u32)section->address + section->size, (u32)firm, (u32)firm + size)) ||
|
||||
((!inRange((u32)section->address, (u32)section->address + section->size, 0x08000000, 0x08000000 + 0x00100000)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x18000000, 0x18000000 + 0x00600000)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x1FF00000, 0x1FFFFC00)) &&
|
||||
(!inRange((u32)section->address, (u32)section->address + section->size, 0x20000000, 0x20000000 + 0x8000000))))
|
||||
return false;
|
||||
|
||||
__attribute__((aligned(4))) u8 hash[0x20];
|
||||
|
||||
sha(hash, (u8 *)firm + section->offset, section->size, SHA_256_MODE);
|
||||
|
||||
if(memcmp(hash, section->hash, 0x20) != 0)
|
||||
return false;
|
||||
|
||||
if(firm->arm9Entry >= section->address && firm->arm9Entry < (section->address + section->size))
|
||||
arm9EpFound = true;
|
||||
|
||||
if(firm->arm11Entry >= section->address && firm->arm11Entry < (section->address + section->size))
|
||||
arm11EpFound = true;
|
||||
}
|
||||
|
||||
return arm9EpFound && (firm->arm11Entry == NULL || arm11EpFound);
|
||||
}
|
||||
|
||||
void launchFirm(int argc, char **argv)
|
||||
{
|
||||
u32 *chainloaderAddress = (u32 *)0x01FF9000;
|
||||
|
||||
prepareArm11ForFirmlaunch();
|
||||
|
||||
memcpy(chainloaderAddress, chainloader_bin, chainloader_bin_size);
|
||||
|
||||
// No need to flush caches here, the chainloader is in ITCM
|
||||
((void (*)(int, char **, u32))chainloaderAddress)(argc, argv, 0x0000BEEF);
|
||||
}
|
||||
|
||||
@@ -1,22 +1,41 @@
|
||||
/*
|
||||
* firm.h
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
#ifndef FIRM_INC
|
||||
#define FIRM_INC
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include "3dsheaders.h"
|
||||
|
||||
#define PDN_MPCORE_CFG (*(u8*)0x10140FFC)
|
||||
#define HID_PAD ((~*(u16*)0x10146000) & 0xFFF)
|
||||
#define BUTTON_R1 (1 << 8)
|
||||
#define BUTTON_L1 (1 << 9)
|
||||
#define SAFEMODE (BUTTON_L1 | BUTTON_R1 | 1 | (1 << 6))
|
||||
static Firm *const firm = (Firm *const)0x20001000;
|
||||
|
||||
void setupCFW(void);
|
||||
u8 loadFirm(void);
|
||||
u8 patchFirm(void);
|
||||
void launchFirm(void);
|
||||
u32 loadFirm(FirmwareType *firmType, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode);
|
||||
u32 patchNativeFirm(u32 firmVersion, FirmwareSource nandType, bool loadFromStorage, bool isSafeMode, bool doUnitinfoPatch, bool enableExceptionHandlers);
|
||||
u32 patchTwlFirm(u32 firmVersion, bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patchAgbFirm(bool loadFromStorage, bool doUnitinfoPatch);
|
||||
u32 patch1x2xNativeAndSafeFirm(bool enableExceptionHandlers);
|
||||
|
||||
#endif
|
||||
bool checkFirmPayload(u32 payloadSize);
|
||||
void launchFirm(int argc, char **argv);
|
||||
|
||||
319
source/fmt.c
Normal file
319
source/fmt.c
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/* File : barebones/ee_printf.c
|
||||
This file contains an implementation of ee_printf that only requires a method to output a char to a UART without pulling in library code.
|
||||
|
||||
This code is based on a file that contains the following:
|
||||
Copyright (C) 2002 Michael Ringgaard. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the project nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
//TuxSH's changes: add support for 64-bit numbers, remove floating-point code
|
||||
|
||||
#include "strings.h"
|
||||
#include "fmt.h"
|
||||
|
||||
#define ZEROPAD (1<<0) //Pad with zero
|
||||
#define SIGN (1<<1) //Unsigned/signed long
|
||||
#define PLUS (1<<2) //Show plus
|
||||
#define SPACE (1<<3) //Spacer
|
||||
#define LEFT (1<<4) //Left justified
|
||||
#define HEX_PREP (1<<5) //0x
|
||||
#define UPPERCASE (1<<6) //'ABCDEF'
|
||||
|
||||
#define IS_DIGIT(c) ((c) >= '0' && (c) <= '9')
|
||||
|
||||
static s32 skipAtoi(const char **s)
|
||||
{
|
||||
s32 i = 0;
|
||||
|
||||
while(IS_DIGIT(**s)) i = i * 10 + *((*s)++) - '0';
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
static char *processNumber(char *str, s64 num, bool isHex, s32 size, s32 precision, u32 type)
|
||||
{
|
||||
char sign = 0;
|
||||
|
||||
if(type & SIGN)
|
||||
{
|
||||
if(num < 0)
|
||||
{
|
||||
sign = '-';
|
||||
num = -num;
|
||||
size--;
|
||||
}
|
||||
else if(type & PLUS)
|
||||
{
|
||||
sign = '+';
|
||||
size--;
|
||||
}
|
||||
else if(type & SPACE)
|
||||
{
|
||||
sign = ' ';
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *lowerDigits = "0123456789abcdef",
|
||||
*upperDigits = "0123456789ABCDEF";
|
||||
|
||||
s32 i = 0;
|
||||
char tmp[20];
|
||||
const char *dig = (type & UPPERCASE) ? upperDigits : lowerDigits;
|
||||
|
||||
if(num == 0)
|
||||
{
|
||||
if(precision != 0) tmp[i++] = '0';
|
||||
type &= ~HEX_PREP;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(num != 0)
|
||||
{
|
||||
u64 base = isHex ? 16ULL : 10ULL;
|
||||
tmp[i++] = dig[(u64)num % base];
|
||||
num = (s64)((u64)num / base);
|
||||
}
|
||||
}
|
||||
|
||||
if(type & LEFT || precision != -1) type &= ~ZEROPAD;
|
||||
if(type & HEX_PREP && isHex) size -= 2;
|
||||
if(i > precision) precision = i;
|
||||
size -= precision;
|
||||
if(!(type & (ZEROPAD | LEFT))) while(size-- > 0) *str++ = ' ';
|
||||
if(sign) *str++ = sign;
|
||||
|
||||
if(type & HEX_PREP && isHex)
|
||||
{
|
||||
*str++ = '0';
|
||||
*str++ = 'x';
|
||||
}
|
||||
|
||||
if(type & ZEROPAD) while(size-- > 0) *str++ = '0';
|
||||
while(i < precision--) *str++ = '0';
|
||||
while(i-- > 0) *str++ = tmp[i];
|
||||
while(size-- > 0) *str++ = ' ';
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
u32 vsprintf(char *buf, const char *fmt, va_list args)
|
||||
{
|
||||
char *str;
|
||||
|
||||
for(str = buf; *fmt; fmt++)
|
||||
{
|
||||
if(*fmt != '%')
|
||||
{
|
||||
*str++ = *fmt;
|
||||
continue;
|
||||
}
|
||||
|
||||
//Process flags
|
||||
u32 flags = 0; //Flags to number()
|
||||
bool loop = true;
|
||||
|
||||
while(loop)
|
||||
{
|
||||
switch(*++fmt)
|
||||
{
|
||||
case '-': flags |= LEFT; break;
|
||||
case '+': flags |= PLUS; break;
|
||||
case ' ': flags |= SPACE; break;
|
||||
case '#': flags |= HEX_PREP; break;
|
||||
case '0': flags |= ZEROPAD; break;
|
||||
default: loop = false; break;
|
||||
}
|
||||
}
|
||||
|
||||
//Get field width
|
||||
s32 fieldWidth = -1; //Width of output field
|
||||
if(IS_DIGIT(*fmt)) fieldWidth = skipAtoi(&fmt);
|
||||
else if(*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
|
||||
fieldWidth = va_arg(args, s32);
|
||||
|
||||
if(fieldWidth < 0)
|
||||
{
|
||||
fieldWidth = -fieldWidth;
|
||||
flags |= LEFT;
|
||||
}
|
||||
}
|
||||
|
||||
//Get the precision
|
||||
s32 precision = -1; //Min. # of digits for integers; max number of chars for from string
|
||||
if(*fmt == '.')
|
||||
{
|
||||
fmt++;
|
||||
|
||||
if(IS_DIGIT(*fmt)) precision = skipAtoi(&fmt);
|
||||
else if(*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
precision = va_arg(args, s32);
|
||||
}
|
||||
|
||||
if(precision < 0) precision = 0;
|
||||
}
|
||||
|
||||
//Get the conversion qualifier
|
||||
u32 integerType = 0;
|
||||
if(*fmt == 'l')
|
||||
{
|
||||
if(*++fmt == 'l')
|
||||
{
|
||||
fmt++;
|
||||
integerType = 1;
|
||||
}
|
||||
|
||||
}
|
||||
else if(*fmt == 'h')
|
||||
{
|
||||
if(*++fmt == 'h')
|
||||
{
|
||||
fmt++;
|
||||
integerType = 3;
|
||||
}
|
||||
else integerType = 2;
|
||||
}
|
||||
|
||||
bool isHex;
|
||||
|
||||
switch(*fmt)
|
||||
{
|
||||
case 'c':
|
||||
if(!(flags & LEFT)) while(--fieldWidth > 0) *str++ = ' ';
|
||||
*str++ = (u8)va_arg(args, s32);
|
||||
while(--fieldWidth > 0) *str++ = ' ';
|
||||
continue;
|
||||
|
||||
case 's':
|
||||
{
|
||||
char *s = va_arg(args, char *);
|
||||
if(!s) s = "<NULL>";
|
||||
u32 len = (precision != -1) ? strnlen(s, precision) : strlen(s);
|
||||
if(!(flags & LEFT)) while((s32)len < fieldWidth--) *str++ = ' ';
|
||||
for(u32 i = 0; i < len; i++) *str++ = *s++;
|
||||
while((s32)len < fieldWidth--) *str++ = ' ';
|
||||
continue;
|
||||
}
|
||||
|
||||
case 'p':
|
||||
if(fieldWidth == -1)
|
||||
{
|
||||
fieldWidth = 8;
|
||||
flags |= ZEROPAD;
|
||||
}
|
||||
str = processNumber(str, va_arg(args, u32), true, fieldWidth, precision, flags);
|
||||
continue;
|
||||
|
||||
//Integer number formats - set up the flags and "break"
|
||||
case 'X':
|
||||
flags |= UPPERCASE;
|
||||
|
||||
case 'x':
|
||||
isHex = true;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
flags |= SIGN;
|
||||
|
||||
case 'u':
|
||||
isHex = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
if(*fmt != '%') *str++ = '%';
|
||||
if(*fmt) *str++ = *fmt;
|
||||
else fmt--;
|
||||
continue;
|
||||
}
|
||||
|
||||
s64 num;
|
||||
|
||||
if(flags & SIGN)
|
||||
{
|
||||
if(integerType == 1) num = va_arg(args, s64);
|
||||
else num = va_arg(args, s32);
|
||||
|
||||
if(integerType == 2) num = (s16)num;
|
||||
else if(integerType == 3) num = (s8)num;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(integerType == 1) num = va_arg(args, u64);
|
||||
else num = va_arg(args, u32);
|
||||
|
||||
if(integerType == 2) num = (u16)num;
|
||||
else if(integerType == 3) num = (u8)num;
|
||||
}
|
||||
|
||||
str = processNumber(str, num, isHex, fieldWidth, precision, flags);
|
||||
}
|
||||
|
||||
*str = 0;
|
||||
return str - buf;
|
||||
}
|
||||
|
||||
u32 sprintf(char *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
u32 res = vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
32
source/fmt.h
Normal file
32
source/fmt.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "memory.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
u32 vsprintf(char *buf, const char *fmt, va_list args);
|
||||
u32 sprintf(char *buf, const char *fmt, ...);
|
||||
144
source/font.h
Normal file
144
source/font.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
This file was autogenerated by raw2c.
|
||||
Visit http://www.devkitpro.org
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
#ifndef _font_h_
|
||||
#define _font_h_
|
||||
//---------------------------------------------------------------------------------
|
||||
static const unsigned char font[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
|
||||
0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
|
||||
0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00,
|
||||
0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
|
||||
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
|
||||
0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
|
||||
0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, 0x08, 0x78, 0xf0, 0x00,
|
||||
0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00,
|
||||
0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
|
||||
0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
|
||||
0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
|
||||
0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e,
|
||||
0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x5a, 0x3c, 0x18, 0x00,
|
||||
0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00,
|
||||
0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00,
|
||||
0x6c, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
|
||||
0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, 0x36, 0x6a, 0xcc, 0x00,
|
||||
0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
|
||||
0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00,
|
||||
0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7e, 0x00,
|
||||
0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00,
|
||||
0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00,
|
||||
0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
|
||||
0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00,
|
||||
0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
|
||||
0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00,
|
||||
0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
|
||||
0x7c, 0x82, 0x9e, 0xa6, 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00,
|
||||
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00,
|
||||
0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
|
||||
0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00,
|
||||
0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
|
||||
0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
|
||||
0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
|
||||
0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
|
||||
0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06,
|
||||
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00,
|
||||
0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
|
||||
0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00,
|
||||
0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00,
|
||||
0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
|
||||
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
|
||||
0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
|
||||
0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
|
||||
0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00,
|
||||
0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00,
|
||||
0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x78,
|
||||
0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
|
||||
0x00, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
|
||||
0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xd6, 0xd6, 0x00,
|
||||
0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
|
||||
0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
|
||||
0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0x7c, 0x00,
|
||||
0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
|
||||
0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00,
|
||||
0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
|
||||
0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00,
|
||||
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00,
|
||||
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
|
||||
0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
|
||||
0x0e, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
|
||||
0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
|
||||
0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70,
|
||||
0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00,
|
||||
0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
|
||||
0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
|
||||
0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
|
||||
0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, 0x7e, 0xd0, 0x7e, 0x00,
|
||||
0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
|
||||
0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
|
||||
0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
|
||||
0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
|
||||
0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00,
|
||||
0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x00,
|
||||
0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
|
||||
0x0e, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
|
||||
0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
|
||||
0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00,
|
||||
0x38, 0x0c, 0x3c, 0x34, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
|
||||
0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00,
|
||||
0xc0, 0xc8, 0xd0, 0xec, 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00,
|
||||
0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00,
|
||||
0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
|
||||
0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
|
||||
0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
|
||||
0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
|
||||
0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
|
||||
0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
|
||||
0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
|
||||
0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
|
||||
0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
|
||||
0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
|
||||
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40,
|
||||
0xfe, 0x62, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00,
|
||||
0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, 0xc8, 0xc8, 0x70, 0x00,
|
||||
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00,
|
||||
0x38, 0x10, 0x7c, 0xd6, 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00,
|
||||
0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
|
||||
0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00,
|
||||
0x00, 0x00, 0x7c, 0xc0, 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
|
||||
0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00,
|
||||
0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00,
|
||||
0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
|
||||
0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
|
||||
0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00,
|
||||
0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
|
||||
};
|
||||
const int font_size = sizeof(font);
|
||||
//---------------------------------------------------------------------------------
|
||||
#endif //_font_h_
|
||||
//---------------------------------------------------------------------------------
|
||||
389
source/fs.c
389
source/fs.c
@@ -1,97 +1,336 @@
|
||||
/*
|
||||
* fs.c
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include "fs.h"
|
||||
#include "memory.h"
|
||||
#include "strings.h"
|
||||
#include "fmt.h"
|
||||
#include "crypto.h"
|
||||
#include "cache.h"
|
||||
#include "screen.h"
|
||||
#include "draw.h"
|
||||
#include "utils.h"
|
||||
#include "config.h"
|
||||
#include "fatfs/ff.h"
|
||||
#include "buttons.h"
|
||||
#include "firm.h"
|
||||
#include "crypto.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
static FATFS fs;
|
||||
static FATFS sdFs,
|
||||
nandFs;
|
||||
|
||||
int mountSD()
|
||||
static bool switchToMainDir(bool isSd)
|
||||
{
|
||||
if (f_mount(&fs, "0:", 1) != FR_OK) {
|
||||
//printF("Failed to mount SD card!");
|
||||
return 1;
|
||||
const char *mainDir = isSd ? "/luma" : "/rw/luma";
|
||||
|
||||
switch(f_chdir(mainDir))
|
||||
{
|
||||
case FR_OK:
|
||||
return true;
|
||||
case FR_NO_PATH:
|
||||
f_mkdir(mainDir);
|
||||
return switchToMainDir(isSd);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
//printF("Mounted SD card");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unmountSD()
|
||||
bool mountFs(bool isSd, bool switchToCtrNand)
|
||||
{
|
||||
if (f_mount(NULL, "0:", 1) != FR_OK) {
|
||||
//printF("Failed to mount SD card!");
|
||||
return 1;
|
||||
return isSd ? f_mount(&sdFs, "0:", 1) == FR_OK && switchToMainDir(true) :
|
||||
f_mount(&nandFs, "1:", 1) == FR_OK && (!switchToCtrNand || (f_chdrive("1:") == FR_OK && switchToMainDir(false)));
|
||||
}
|
||||
|
||||
u32 fileRead(void *dest, const char *path, u32 maxSize)
|
||||
{
|
||||
FIL file;
|
||||
u32 ret = 0;
|
||||
|
||||
if(f_open(&file, path, FA_READ) != FR_OK) return ret;
|
||||
|
||||
u32 size = f_size(&file);
|
||||
if(dest == NULL) ret = size;
|
||||
else if(size <= maxSize)
|
||||
f_read(&file, dest, size, (unsigned int *)&ret);
|
||||
f_close(&file);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u32 getFileSize(const char *path)
|
||||
{
|
||||
return fileRead(NULL, path, 0);
|
||||
}
|
||||
|
||||
bool fileWrite(const void *buffer, const char *path, u32 size)
|
||||
{
|
||||
FIL file;
|
||||
|
||||
switch(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS))
|
||||
{
|
||||
case FR_OK:
|
||||
{
|
||||
unsigned int written;
|
||||
f_write(&file, buffer, size, &written);
|
||||
f_truncate(&file);
|
||||
f_close(&file);
|
||||
|
||||
return (u32)written == size;
|
||||
}
|
||||
case FR_NO_PATH:
|
||||
for(u32 i = 1; path[i] != 0; i++)
|
||||
if(path[i] == '/')
|
||||
{
|
||||
char folder[i + 1];
|
||||
memcpy(folder, path, i);
|
||||
folder[i] = 0;
|
||||
f_mkdir(folder);
|
||||
}
|
||||
|
||||
return fileWrite(buffer, path, size);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
//printF("Unmounted SD card");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fileReadOffset(u8 *dest, const char *path, u32 size, u32 offset){
|
||||
FRESULT fr;
|
||||
FIL fp;
|
||||
unsigned int br = 0;
|
||||
|
||||
fr = f_open(&fp, path, FA_READ);
|
||||
if (fr != FR_OK)goto error;
|
||||
|
||||
if (!size) size = f_size(&fp);
|
||||
if (offset) {
|
||||
fr = f_lseek(&fp, offset);
|
||||
if (fr != FR_OK) goto error;
|
||||
}
|
||||
|
||||
fr = f_read(&fp, dest, size, &br);
|
||||
if (fr != FR_OK) goto error;
|
||||
|
||||
fr = f_close(&fp);
|
||||
if (fr != FR_OK) goto error;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
f_close(&fp);
|
||||
return fr;
|
||||
}
|
||||
|
||||
int fileRead(u8 *dest, const char *path, u32 size){
|
||||
return fileReadOffset(dest, path, size, 0);
|
||||
}
|
||||
|
||||
int fileWrite(const u8 *buffer, const char *path, u32 size){
|
||||
FRESULT fr = 1;
|
||||
FIL fp;
|
||||
unsigned int br = 0;
|
||||
|
||||
void fileDelete(const char *path)
|
||||
{
|
||||
f_unlink(path);
|
||||
if(f_open(&fp, path, FA_WRITE | FA_OPEN_ALWAYS) == FR_OK){
|
||||
fr = f_write(&fp, buffer, size, &br);
|
||||
f_close(&fp);
|
||||
if (fr == FR_OK && br == size) return 0;
|
||||
}
|
||||
|
||||
void loadPayload(u32 pressed, const char *payloadPath)
|
||||
{
|
||||
u32 payloadSize = 0,
|
||||
maxPayloadSize = (u32)((u8 *)0x27FFE000 - (u8 *)firm);
|
||||
|
||||
char absPath[24 + _MAX_LFN];
|
||||
char path[10 + _MAX_LFN];
|
||||
|
||||
if(payloadPath == NULL)
|
||||
{
|
||||
const char *pattern;
|
||||
|
||||
if(pressed & BUTTON_LEFT) pattern = PATTERN("left");
|
||||
else if(pressed & BUTTON_RIGHT) pattern = PATTERN("right");
|
||||
else if(pressed & BUTTON_UP) pattern = PATTERN("up");
|
||||
else if(pressed & BUTTON_DOWN) pattern = PATTERN("down");
|
||||
else if(pressed & BUTTON_START) pattern = PATTERN("start");
|
||||
else if(pressed & BUTTON_B) pattern = PATTERN("b");
|
||||
else if(pressed & BUTTON_X) pattern = PATTERN("x");
|
||||
else if(pressed & BUTTON_Y) pattern = PATTERN("y");
|
||||
else if(pressed & BUTTON_R1) pattern = PATTERN("r");
|
||||
else if(pressed & BUTTON_A) pattern = PATTERN("a");
|
||||
else pattern = PATTERN("select");
|
||||
|
||||
DIR dir;
|
||||
FILINFO info;
|
||||
FRESULT result;
|
||||
|
||||
result = f_findfirst(&dir, &info, "payloads", pattern);
|
||||
|
||||
if(result != FR_OK) return;
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(!info.fname[0]) return;
|
||||
|
||||
sprintf(path, "payloads/%s", info.fname);
|
||||
|
||||
}
|
||||
return fr;
|
||||
else sprintf(path, "%s", payloadPath);
|
||||
|
||||
payloadSize = fileRead(firm, path, maxPayloadSize);
|
||||
|
||||
if(payloadSize <= 0x200 || !checkFirmPayload(payloadSize)) return;
|
||||
|
||||
writeConfig(true);
|
||||
|
||||
if(isSdMode) sprintf(absPath, "sdmc:/luma/%s", path);
|
||||
else sprintf(absPath, "nand:/rw/luma/%s", path);
|
||||
|
||||
char *argv[2] = {absPath, (char *)fbs};
|
||||
initScreens();
|
||||
|
||||
launchFirm((firm->reserved2[0] & 1) ? 2 : 1, argv);
|
||||
}
|
||||
|
||||
int fileSize(const char* path){
|
||||
FRESULT fr;
|
||||
FIL fp;
|
||||
int size = 0;
|
||||
void payloadMenu(void)
|
||||
{
|
||||
DIR dir;
|
||||
char path[62] = "payloads";
|
||||
|
||||
fr = f_open(&fp, path, FA_READ);
|
||||
if (fr != FR_OK)goto error;
|
||||
|
||||
size = f_size(&fp);
|
||||
error:
|
||||
f_close(&fp);
|
||||
return size;
|
||||
if(f_opendir(&dir, path) != FR_OK) return;
|
||||
|
||||
FILINFO info;
|
||||
u32 payloadNum = 0;
|
||||
char payloadList[20][49];
|
||||
|
||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 20)
|
||||
{
|
||||
if(info.fname[0] == '.') continue;
|
||||
|
||||
u32 nameLength = strlen(info.fname);
|
||||
|
||||
if(nameLength < 6 || nameLength > 52) continue;
|
||||
|
||||
nameLength -= 5;
|
||||
|
||||
if(memcmp(info.fname + nameLength, ".firm", 5) != 0) continue;
|
||||
|
||||
memcpy(payloadList[payloadNum], info.fname, nameLength);
|
||||
payloadList[payloadNum][nameLength] = 0;
|
||||
payloadNum++;
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(!payloadNum) return;
|
||||
|
||||
u32 pressed = 0,
|
||||
selectedPayload = 0;
|
||||
|
||||
if(payloadNum != 1)
|
||||
{
|
||||
initScreens();
|
||||
|
||||
drawString(true, 10, 10, COLOR_TITLE, "Luma3DS chainloader");
|
||||
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press A to select, START to quit");
|
||||
|
||||
for(u32 i = 0, posY = 10 + 3 * SPACING_Y, color = COLOR_RED; i < payloadNum; i++, posY += SPACING_Y)
|
||||
{
|
||||
drawString(true, 10, posY, color, payloadList[i]);
|
||||
if(color == COLOR_RED) color = COLOR_WHITE;
|
||||
}
|
||||
|
||||
while(pressed != BUTTON_A && pressed != BUTTON_START)
|
||||
{
|
||||
do
|
||||
{
|
||||
pressed = waitInput(true);
|
||||
}
|
||||
while(!(pressed & MENU_BUTTONS));
|
||||
|
||||
u32 oldSelectedPayload = selectedPayload;
|
||||
|
||||
switch(pressed)
|
||||
{
|
||||
case BUTTON_UP:
|
||||
selectedPayload = !selectedPayload ? payloadNum - 1 : selectedPayload - 1;
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
selectedPayload = selectedPayload == payloadNum - 1 ? 0 : selectedPayload + 1;
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
selectedPayload = 0;
|
||||
break;
|
||||
case BUTTON_RIGHT:
|
||||
selectedPayload = payloadNum - 1;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
if(oldSelectedPayload == selectedPayload) continue;
|
||||
|
||||
drawString(true, 10, 10 + (3 + oldSelectedPayload) * SPACING_Y, COLOR_WHITE, payloadList[oldSelectedPayload]);
|
||||
drawString(true, 10, 10 + (3 + selectedPayload) * SPACING_Y, COLOR_RED, payloadList[selectedPayload]);
|
||||
}
|
||||
}
|
||||
|
||||
if(pressed != BUTTON_START)
|
||||
{
|
||||
sprintf(path, "payloads/%s.firm", payloadList[selectedPayload]);
|
||||
loadPayload(0, path);
|
||||
error("The payload is too large or corrupted.");
|
||||
}
|
||||
|
||||
while(HID_PAD & MENU_BUTTONS);
|
||||
wait(2000ULL);
|
||||
}
|
||||
|
||||
int fileExists(const char* path){
|
||||
FRESULT fr;
|
||||
FIL fp;
|
||||
int exists = 1;
|
||||
fr = f_open(&fp, path, FA_READ);
|
||||
if (fr != FR_OK)exists = 0;
|
||||
f_close(&fp);
|
||||
return exists;
|
||||
}
|
||||
u32 firmRead(void *dest, u32 firmType)
|
||||
{
|
||||
const char *firmFolders[][2] = {{"00000002", "20000002"},
|
||||
{"00000102", "20000102"},
|
||||
{"00000202", "20000202"},
|
||||
{"00000003", "20000003"},
|
||||
{"00000001", "20000001"}};
|
||||
|
||||
char folderPath[35],
|
||||
path[48];
|
||||
|
||||
sprintf(folderPath, "1:/title/00040138/%s/content", firmFolders[firmType][ISN3DS ? 1 : 0]);
|
||||
|
||||
DIR dir;
|
||||
u32 firmVersion = 0xFFFFFFFF;
|
||||
|
||||
if(f_opendir(&dir, folderPath) != FR_OK) goto exit;
|
||||
|
||||
FILINFO info;
|
||||
|
||||
//Parse the target directory
|
||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
|
||||
{
|
||||
//Not a cxi
|
||||
if(info.fname[9] != 'a' || strlen(info.fname) != 12) continue;
|
||||
|
||||
u32 tempVersion = hexAtoi(info.altname, 8);
|
||||
|
||||
//Found an older cxi
|
||||
if(tempVersion < firmVersion) firmVersion = tempVersion;
|
||||
}
|
||||
|
||||
f_closedir(&dir);
|
||||
|
||||
if(firmVersion == 0xFFFFFFFF) goto exit;
|
||||
|
||||
//Complete the string with the .app name
|
||||
sprintf(path, "%s/%08x.app", folderPath, firmVersion);
|
||||
|
||||
if(fileRead(dest, path, 0x400000 + sizeof(Cxi) + 0x200) <= sizeof(Cxi) + 0x200) firmVersion = 0xFFFFFFFF;
|
||||
|
||||
exit:
|
||||
return firmVersion;
|
||||
}
|
||||
|
||||
void findDumpFile(const char *folderPath, char *fileName)
|
||||
{
|
||||
DIR dir;
|
||||
FRESULT result;
|
||||
|
||||
for(u32 n = 0; n <= 99999999; n++)
|
||||
{
|
||||
FILINFO info;
|
||||
|
||||
sprintf(fileName, "crash_dump_%08u.dmp", n);
|
||||
result = f_findfirst(&dir, &info, folderPath, fileName);
|
||||
|
||||
if(result != FR_OK || !info.fname[0]) break;
|
||||
}
|
||||
|
||||
if(result == FR_OK) f_closedir(&dir);
|
||||
}
|
||||
|
||||
45
source/fs.h
45
source/fs.h
@@ -1,18 +1,41 @@
|
||||
/*
|
||||
* fs.h
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#ifndef __fs_h__
|
||||
#define __fs_h__
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
int mountSD();
|
||||
int unmountSD();
|
||||
int fileReadOffset(u8 *dest, const char *path, u32 size, u32 offset);
|
||||
int fileRead(u8 *dest, const char *path, u32 size);
|
||||
int fileWrite(const u8 *buffer, const char *path, u32 size);
|
||||
int fileSize(const char* path);
|
||||
int fileExists(const char* path);
|
||||
#define PATTERN(a) a "_*.firm"
|
||||
|
||||
#endif
|
||||
bool mountFs(bool isSd, bool switchToCtrNand);
|
||||
u32 fileRead(void *dest, const char *path, u32 maxSize);
|
||||
u32 getFileSize(const char *path);
|
||||
bool fileWrite(const void *buffer, const char *path, u32 size);
|
||||
void fileDelete(const char *path);
|
||||
void loadPayload(u32 pressed, const char *payloadPath);
|
||||
void payloadMenu(void);
|
||||
u32 firmRead(void *dest, u32 firmType);
|
||||
void findDumpFile(const char *folderPath, char *fileName);
|
||||
|
||||
176
source/i2c.c
Normal file
176
source/i2c.c
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Thanks to whoever contributed in the development of this file
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "i2c.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static const struct { u8 bus_id, reg_addr; } dev_data[] = {
|
||||
{0, 0x4A}, {0, 0x7A}, {0, 0x78},
|
||||
{1, 0x4A}, {1, 0x78}, {1, 0x2C},
|
||||
{1, 0x2E}, {1, 0x40}, {1, 0x44},
|
||||
{2, 0xD6}, {2, 0xD0}, {2, 0xD2},
|
||||
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
|
||||
};
|
||||
|
||||
static inline u8 i2cGetDeviceBusId(u8 device_id)
|
||||
{
|
||||
return dev_data[device_id].bus_id;
|
||||
}
|
||||
|
||||
static inline u8 i2cGetDeviceRegAddr(u8 device_id)
|
||||
{
|
||||
return dev_data[device_id].reg_addr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static vu8 *reg_data_addrs[] = {
|
||||
(vu8 *)(I2C1_REG_OFF + I2C_REG_DATA),
|
||||
(vu8 *)(I2C2_REG_OFF + I2C_REG_DATA),
|
||||
(vu8 *)(I2C3_REG_OFF + I2C_REG_DATA),
|
||||
};
|
||||
|
||||
static inline vu8 *i2cGetDataReg(u8 bus_id)
|
||||
{
|
||||
return reg_data_addrs[bus_id];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static vu8 *reg_cnt_addrs[] = {
|
||||
(vu8 *)(I2C1_REG_OFF + I2C_REG_CNT),
|
||||
(vu8 *)(I2C2_REG_OFF + I2C_REG_CNT),
|
||||
(vu8 *)(I2C3_REG_OFF + I2C_REG_CNT),
|
||||
};
|
||||
|
||||
static inline vu8 *i2cGetCntReg(u8 bus_id)
|
||||
{
|
||||
return reg_cnt_addrs[bus_id];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static inline void i2cWaitBusy(u8 bus_id)
|
||||
{
|
||||
while (*i2cGetCntReg(bus_id) & 0x80);
|
||||
}
|
||||
|
||||
static inline bool i2cGetResult(u8 bus_id)
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
|
||||
return (*i2cGetCntReg(bus_id) >> 4) & 1;
|
||||
}
|
||||
|
||||
static void i2cStop(u8 bus_id, u8 arg0)
|
||||
{
|
||||
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static bool i2cSelectDevice(u8 bus_id, u8 dev_reg)
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = dev_reg;
|
||||
*i2cGetCntReg(bus_id) = 0xC2;
|
||||
|
||||
return i2cGetResult(bus_id);
|
||||
}
|
||||
|
||||
static bool i2cSelectRegister(u8 bus_id, u8 reg)
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = reg;
|
||||
*i2cGetCntReg(bus_id) = 0xC0;
|
||||
|
||||
return i2cGetResult(bus_id);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
u8 i2cReadRegister(u8 dev_id, u8 reg)
|
||||
{
|
||||
u8 bus_id = i2cGetDeviceBusId(dev_id),
|
||||
dev_addr = i2cGetDeviceRegAddr(dev_id),
|
||||
ret = 0xFF;
|
||||
|
||||
for(u32 i = 0; i < 8 && ret == 0xFF; i++)
|
||||
{
|
||||
if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
|
||||
{
|
||||
if(i2cSelectDevice(bus_id, dev_addr | 1))
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
i2cStop(bus_id, 1);
|
||||
i2cWaitBusy(bus_id);
|
||||
|
||||
ret = *i2cGetDataReg(bus_id);
|
||||
}
|
||||
}
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
i2cWaitBusy(bus_id);
|
||||
}
|
||||
|
||||
wait(3ULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
|
||||
{
|
||||
u8 bus_id = i2cGetDeviceBusId(dev_id),
|
||||
dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||
|
||||
bool ret = false;
|
||||
|
||||
for(u32 i = 0; i < 8 && !ret; i++)
|
||||
{
|
||||
if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
|
||||
{
|
||||
i2cWaitBusy(bus_id);
|
||||
*i2cGetDataReg(bus_id) = data;
|
||||
*i2cGetCntReg(bus_id) = 0xC1;
|
||||
i2cStop(bus_id, 0);
|
||||
|
||||
if(i2cGetResult(bus_id)) ret = true;
|
||||
}
|
||||
*i2cGetCntReg(bus_id) = 0xC5;
|
||||
i2cWaitBusy(bus_id);
|
||||
}
|
||||
|
||||
wait(3ULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
49
source/i2c.h
Normal file
49
source/i2c.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Thanks to whoever contributed in the development of this file
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define I2C1_REG_OFF 0x10161000
|
||||
#define I2C2_REG_OFF 0x10144000
|
||||
#define I2C3_REG_OFF 0x10148000
|
||||
|
||||
#define I2C_REG_DATA 0
|
||||
#define I2C_REG_CNT 1
|
||||
#define I2C_REG_CNTEX 2
|
||||
#define I2C_REG_SCL 4
|
||||
|
||||
#define I2C_DEV_MCU 3
|
||||
#define I2C_DEV_GYRO 10
|
||||
#define I2C_DEV_IR 13
|
||||
|
||||
u8 i2cReadRegister(u8 dev_id, u8 reg);
|
||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
|
||||
320
source/main.c
320
source/main.c
@@ -1,21 +1,315 @@
|
||||
/*
|
||||
* main.c
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* Minimalist CFW for N3DS
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "emunand.h"
|
||||
#include "fs.h"
|
||||
#include "firm.h"
|
||||
#include "utils.h"
|
||||
#include "exceptions.h"
|
||||
#include "draw.h"
|
||||
#include "strings.h"
|
||||
#include "buttons.h"
|
||||
#include "pin.h"
|
||||
#include "crypto.h"
|
||||
#include "memory.h"
|
||||
#include "screen.h"
|
||||
|
||||
u8 main(){
|
||||
mountSD();
|
||||
loadSplash();
|
||||
setupCFW();
|
||||
if (loadFirm()) return 1;
|
||||
if (patchFirm()) return 1;
|
||||
launchFirm();
|
||||
return 0;
|
||||
}
|
||||
extern CfgData configData;
|
||||
extern ConfigurationStatus needConfig;
|
||||
extern FirmwareSource firmSource;
|
||||
|
||||
bool isFirmlaunch = false,
|
||||
isSdMode;
|
||||
u16 launchedPath[41];
|
||||
|
||||
void main(int argc, char **argv, u32 magicWord)
|
||||
{
|
||||
bool isSafeMode = false,
|
||||
isNoForceFlagSet = false;
|
||||
FirmwareType firmType;
|
||||
FirmwareSource nandType;
|
||||
|
||||
if((magicWord & 0xFFFF) == 0xBEEF && argc >= 1) //Normal boot
|
||||
{
|
||||
u32 i;
|
||||
for(i = 0; i < 40 && argv[0][i] != 0; i++) //Copy and convert the path to UTF-16
|
||||
launchedPath[i] = argv[0][i];
|
||||
launchedPath[i] = 0;
|
||||
}
|
||||
else if(magicWord == 0xBABE && argc == 2) //Firmlaunch
|
||||
{
|
||||
u32 i;
|
||||
u16 *p = (u16 *)argv[0];
|
||||
for(i = 0; i < 40 && p[i] != 0; i++)
|
||||
launchedPath[i] = p[i];
|
||||
launchedPath[i] = 0;
|
||||
|
||||
isFirmlaunch = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char argv[] = "firm0:";
|
||||
for(u32 i = 0; i < sizeof(argv); i++) //Copy and convert the path to UTF-16
|
||||
launchedPath[i] = argv[i];
|
||||
}
|
||||
|
||||
if(memcmp(launchedPath, u"sdmc", 8) == 0)
|
||||
{
|
||||
if(!mountFs(true, false)) error("Failed to mount SD.");
|
||||
isSdMode = true;
|
||||
}
|
||||
else if(memcmp(launchedPath, u"nand", 8) == 0)
|
||||
{
|
||||
firmSource = FIRMWARE_SYSNAND;
|
||||
if(!mountFs(false, true)) error("Failed to mount CTRNAND.");
|
||||
isSdMode = false;
|
||||
}
|
||||
else if(memcmp(launchedPath, u"firm", 8) == 0)
|
||||
{
|
||||
setupKeyslots();
|
||||
|
||||
if(mountFs(true, false)) isSdMode = true;
|
||||
else if(mountFs(false, true)) isSdMode = false;
|
||||
else error("Failed to mount SD and CTRNAND.");
|
||||
}
|
||||
else
|
||||
{
|
||||
char mountPoint[5];
|
||||
|
||||
u32 i;
|
||||
for(i = 0; i < 4 && launchedPath[i] != u':'; i++)
|
||||
mountPoint[i] = (char)launchedPath[i];
|
||||
mountPoint[i] = 0;
|
||||
|
||||
error("Launched from an unsupported location: %s.", mountPoint);
|
||||
}
|
||||
|
||||
//Attempt to read the configuration file
|
||||
needConfig = readConfig() ? MODIFY_CONFIGURATION : CREATE_CONFIGURATION;
|
||||
|
||||
//Determine if this is a firmlaunch boot
|
||||
if(isFirmlaunch)
|
||||
{
|
||||
if(needConfig == CREATE_CONFIGURATION) mcuPowerOff();
|
||||
|
||||
switch(argv[1][14])
|
||||
{
|
||||
case '2':
|
||||
firmType = (FirmwareType)(argv[1][10] - '0');
|
||||
break;
|
||||
case '3':
|
||||
firmType = SAFE_FIRM;
|
||||
break;
|
||||
case '1':
|
||||
firmType = SYSUPDATER_FIRM;
|
||||
break;
|
||||
}
|
||||
|
||||
nandType = (FirmwareSource)BOOTCFG_NAND;
|
||||
firmSource = (FirmwareSource)BOOTCFG_FIRM;
|
||||
|
||||
goto boot;
|
||||
}
|
||||
|
||||
detectAndProcessExceptionDumps();
|
||||
installArm9Handlers();
|
||||
|
||||
firmType = NATIVE_FIRM;
|
||||
|
||||
//Get pressed buttons
|
||||
u32 pressed = HID_PAD;
|
||||
|
||||
//If it's a MCU reboot, try to force boot options
|
||||
if(CFG_BOOTENV && needConfig != CREATE_CONFIGURATION)
|
||||
{
|
||||
|
||||
//Always force a SysNAND boot when quitting AGB_FIRM
|
||||
if(CFG_BOOTENV == 7)
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = (BOOTCFG_NAND != 0) == (BOOTCFG_FIRM != 0) ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCFG_FIRM;
|
||||
|
||||
//Prevent multiple boot options-forcing
|
||||
isNoForceFlagSet = true;
|
||||
|
||||
goto boot;
|
||||
}
|
||||
|
||||
/* Else, force the last used boot options unless a button is pressed
|
||||
or the no-forcing flag is set */
|
||||
if(!pressed && !BOOTCFG_NOFORCEFLAG)
|
||||
{
|
||||
nandType = (FirmwareSource)BOOTCFG_NAND;
|
||||
firmSource = (FirmwareSource)BOOTCFG_FIRM;
|
||||
|
||||
goto boot;
|
||||
}
|
||||
}
|
||||
|
||||
u32 pinMode = MULTICONFIG(PIN);
|
||||
bool pinExists = pinMode != 0 && verifyPin(pinMode);
|
||||
|
||||
//If no configuration file exists or SELECT is held, load configuration menu
|
||||
bool shouldLoadConfigMenu = needConfig == CREATE_CONFIGURATION || ((pressed & (BUTTON_SELECT | BUTTON_L1)) == BUTTON_SELECT);
|
||||
|
||||
if(shouldLoadConfigMenu)
|
||||
{
|
||||
configMenu(pinExists, pinMode);
|
||||
|
||||
//Update pressed buttons
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
|
||||
if(!CFG_BOOTENV && pressed == SAFE_MODE)
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = FIRMWARE_SYSNAND;
|
||||
|
||||
isSafeMode = true;
|
||||
|
||||
//If the PIN has been verified, wait to make it easier to press the SAFE_MODE combo
|
||||
if(pinExists && !shouldLoadConfigMenu)
|
||||
{
|
||||
while(HID_PAD & PIN_BUTTONS);
|
||||
wait(2000ULL);
|
||||
}
|
||||
|
||||
goto boot;
|
||||
}
|
||||
|
||||
u32 splashMode = MULTICONFIG(SPLASH);
|
||||
|
||||
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
|
||||
|
||||
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
|
||||
{
|
||||
payloadMenu();
|
||||
pressed = HID_PAD;
|
||||
}
|
||||
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
|
||||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
|
||||
|
||||
if(splashMode == 2) loadSplash();
|
||||
|
||||
//If booting from CTRNAND, always use SysNAND
|
||||
if(!isSdMode) nandType = FIRMWARE_SYSNAND;
|
||||
|
||||
//If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
|
||||
else if(pressed & BUTTON_R1)
|
||||
{
|
||||
if(CONFIG(USEEMUFIRM))
|
||||
{
|
||||
nandType = FIRMWARE_SYSNAND;
|
||||
firmSource = FIRMWARE_EMUNAND;
|
||||
}
|
||||
else
|
||||
{
|
||||
nandType = FIRMWARE_EMUNAND;
|
||||
firmSource = FIRMWARE_SYSNAND;
|
||||
}
|
||||
}
|
||||
|
||||
/* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
|
||||
with their own FIRM */
|
||||
else firmSource = nandType = (CONFIG(AUTOBOOTEMU) == ((pressed & BUTTON_L1) == BUTTON_L1)) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
|
||||
|
||||
//If we're booting EmuNAND or using EmuNAND FIRM, determine which one from the directional pad buttons, or otherwise from the config
|
||||
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
|
||||
{
|
||||
FirmwareSource tempNand;
|
||||
switch(pressed & DPAD_BUTTONS)
|
||||
{
|
||||
case BUTTON_UP:
|
||||
tempNand = FIRMWARE_EMUNAND;
|
||||
break;
|
||||
case BUTTON_RIGHT:
|
||||
tempNand = FIRMWARE_EMUNAND2;
|
||||
break;
|
||||
case BUTTON_DOWN:
|
||||
tempNand = FIRMWARE_EMUNAND3;
|
||||
break;
|
||||
case BUTTON_LEFT:
|
||||
tempNand = FIRMWARE_EMUNAND4;
|
||||
break;
|
||||
default:
|
||||
tempNand = (FirmwareSource)(1 + MULTICONFIG(DEFAULTEMU));
|
||||
break;
|
||||
}
|
||||
|
||||
if(nandType == FIRMWARE_EMUNAND) nandType = tempNand;
|
||||
else firmSource = tempNand;
|
||||
}
|
||||
|
||||
boot:
|
||||
|
||||
//If we need to boot EmuNAND, make sure it exists
|
||||
if(nandType != FIRMWARE_SYSNAND)
|
||||
{
|
||||
locateEmuNand(&nandType);
|
||||
if(nandType == FIRMWARE_SYSNAND) firmSource = FIRMWARE_SYSNAND;
|
||||
}
|
||||
|
||||
//Same if we're using EmuNAND as the FIRM source
|
||||
else if(firmSource != FIRMWARE_SYSNAND)
|
||||
locateEmuNand(&firmSource);
|
||||
|
||||
if(!isFirmlaunch)
|
||||
{
|
||||
configData.config = (configData.config & 0xFFFFFF80) | ((u32)isNoForceFlagSet << 6) | ((u32)firmSource << 3) | (u32)nandType;
|
||||
writeConfig(false);
|
||||
}
|
||||
|
||||
if(isSdMode && !mountFs(false, false)) error("Failed to mount CTRNAND.");
|
||||
|
||||
bool loadFromStorage = CONFIG(LOADEXTFIRMSANDMODULES);
|
||||
u32 firmVersion = loadFirm(&firmType, firmSource, loadFromStorage, isSafeMode);
|
||||
|
||||
bool doUnitinfoPatch = CONFIG(PATCHUNITINFO), enableExceptionHandlers = CONFIG(PATCHUNITINFO);
|
||||
u32 res;
|
||||
switch(firmType)
|
||||
{
|
||||
case NATIVE_FIRM:
|
||||
res = patchNativeFirm(firmVersion, nandType, loadFromStorage, isSafeMode, doUnitinfoPatch, enableExceptionHandlers);
|
||||
break;
|
||||
case TWL_FIRM:
|
||||
res = patchTwlFirm(firmVersion, loadFromStorage, doUnitinfoPatch);
|
||||
break;
|
||||
case AGB_FIRM:
|
||||
res = patchAgbFirm(loadFromStorage, doUnitinfoPatch);
|
||||
break;
|
||||
case SAFE_FIRM:
|
||||
case SYSUPDATER_FIRM:
|
||||
case NATIVE_FIRM1X2X:
|
||||
res = patch1x2xNativeAndSafeFirm(enableExceptionHandlers);
|
||||
break;
|
||||
}
|
||||
|
||||
if(res != 0) error("Failed to apply %u FIRM patch(es).", res);
|
||||
|
||||
if(!isFirmlaunch) deinitScreens();
|
||||
launchFirm(0, NULL);
|
||||
}
|
||||
|
||||
104
source/memory.c
104
source/memory.c
@@ -1,42 +1,96 @@
|
||||
/*
|
||||
* memory.c
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Boyer-Moore Horspool algorithm adapted from http://www-igm.univ-mlv.fr/~lecroq/string/node18.html#SECTION00180
|
||||
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||
*/
|
||||
|
||||
#include "memory.h"
|
||||
|
||||
void memcpy32(u32 *dest, u32 *src, u32 size){
|
||||
for (u32 i = 0; i < size; i++) dest[i] = src[i];
|
||||
}
|
||||
void memcpy(void *dest, const void *src, u32 size)
|
||||
{
|
||||
u8 *destc = (u8 *)dest;
|
||||
const u8 *srcc = (const u8 *)src;
|
||||
|
||||
void memcpy(void *dest, const void *src, u32 size){
|
||||
char *destc = (char *)dest;
|
||||
const char *srcc = (const char *)src;
|
||||
u32 i; for (i = 0; i < size; i++) {
|
||||
for(u32 i = 0; i < size; i++)
|
||||
destc[i] = srcc[i];
|
||||
}
|
||||
}
|
||||
|
||||
void memset(void *dest, int filler, u32 size){
|
||||
char *destc = (char *)dest;
|
||||
u32 i; for (i = 0; i < size; i++) {
|
||||
destc[i] = filler;
|
||||
}
|
||||
void *memset(void *dest, u32 value, u32 size)
|
||||
{
|
||||
u8 *destc = (u8 *)dest;
|
||||
|
||||
for(u32 i = 0; i < size; i++) destc[i] = (u8)value;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
int memcmp(const void *buf1, const void *buf2, u32 size){
|
||||
const char *buf1c = (const char *)buf1;
|
||||
const char *buf2c = (const char *)buf2;
|
||||
u32 i; for (i = 0; i < size; i++) {
|
||||
void memset32(void *dest, u32 filler, u32 size)
|
||||
{
|
||||
u32 *dest32 = (u32 *)dest;
|
||||
|
||||
for(u32 i = 0; i < size / 4; i++)
|
||||
dest32[i] = filler;
|
||||
}
|
||||
|
||||
int memcmp(const void *buf1, const void *buf2, u32 size)
|
||||
{
|
||||
const u8 *buf1c = (const u8 *)buf1,
|
||||
*buf2c = (const u8 *)buf2;
|
||||
|
||||
for(u32 i = 0; i < size; i++)
|
||||
{
|
||||
int cmp = buf1c[i] - buf2c[i];
|
||||
if (cmp) return cmp;
|
||||
if(cmp != 0) return cmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search){
|
||||
for (void *pos = start_pos + size - size_search; pos >= start_pos; pos--) {
|
||||
if (memcmp(pos, search, size_search) == 0) return pos;
|
||||
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
|
||||
{
|
||||
const u8 *patternc = (const u8 *)pattern;
|
||||
u32 table[256];
|
||||
|
||||
//Preprocessing
|
||||
for(u32 i = 0; i < 256; i++)
|
||||
table[i] = patternSize;
|
||||
for(u32 i = 0; i < patternSize - 1; i++)
|
||||
table[patternc[i]] = patternSize - i - 1;
|
||||
|
||||
//Searching
|
||||
u32 j = 0;
|
||||
while(j <= size - patternSize)
|
||||
{
|
||||
u8 c = startPos[j + patternSize - 1];
|
||||
if(patternc[patternSize - 1] == c && memcmp(pattern, startPos + j, patternSize - 1) == 0)
|
||||
return startPos + j;
|
||||
j += table[c];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,40 @@
|
||||
/*
|
||||
* memory.h
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
#ifndef MEM_INC
|
||||
#define MEM_INC
|
||||
|
||||
/*
|
||||
* Boyer-Moore Horspool algorithm adapted from http://www-igm.univ-mlv.fr/~lecroq/string/node18.html#SECTION00180
|
||||
* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
void memcpy(void *dest, const void *src, u32 size);
|
||||
void memcpy32(u32 *dest, u32 *src, u32 size);
|
||||
void memset(void *dest, int filler, u32 size);
|
||||
void *memset(void *dest, u32 value, u32 size) __attribute__((used));
|
||||
void memset32(void *dest, u32 filler, u32 size);
|
||||
int memcmp(const void *buf1, const void *buf2, u32 size);
|
||||
void *memsearch(void *start_pos, void *search, u32 size, u32 size_search);
|
||||
|
||||
#endif
|
||||
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);
|
||||
|
||||
608
source/patches.c
608
source/patches.c
@@ -1,69 +1,587 @@
|
||||
/*
|
||||
* patches.c
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Signature patches by an unknown author
|
||||
* Signature patches for old FIRMs by SciresM
|
||||
* firmlaunches patching code originally by delebile
|
||||
* FIRM partition writes patches by delebile
|
||||
* Idea for svcBreak patches from yellows8 and others on #3dsdev
|
||||
* TWL_FIRM patches by Steveice10 and others
|
||||
*/
|
||||
|
||||
#include "patches.h"
|
||||
#include "fs.h"
|
||||
#include "exceptions.h"
|
||||
#include "memory.h"
|
||||
#include "config.h"
|
||||
#include "utils.h"
|
||||
#include "../build/bundled.h"
|
||||
|
||||
/**************************************************
|
||||
* Patches
|
||||
**************************************************/
|
||||
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr)
|
||||
{
|
||||
u8 *temp = memsearch(pos, "NCCH", size, 4);
|
||||
|
||||
/*
|
||||
* MPU
|
||||
*/
|
||||
u8 mpu[0x2C] = { //MPU shit
|
||||
0x03, 0x00, 0x36, 0x00, 0x00, 0x00, 0x10, 0x10, 0x01, 0x00, 0x00, 0x01, 0x03, 0x00, 0x36, 0x00,
|
||||
0x00, 0x00, 0x00, 0x20, 0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x20, 0x00, 0x00, 0x00, 0x00, 0x08,
|
||||
0x01, 0x01, 0x01, 0x01, 0x03, 0x06, 0x1C, 0x00, 0x00, 0x00, 0x02, 0x08
|
||||
};
|
||||
if(temp == NULL) error("Failed to get Process9 data.");
|
||||
|
||||
u8 nandRedir[0x08] = {0x00, 0x4C, 0xA0, 0x47, 0xC0, 0xA5, 0x01, 0x08}; //Branch to emunand function
|
||||
Cxi *off = (Cxi *)(temp - 0x100);
|
||||
|
||||
/*
|
||||
* Sig checks
|
||||
*/
|
||||
u8 sigPat1[2] = {0x00, 0x20};
|
||||
u8 sigPat2[4] = {0x00, 0x20, 0x70, 0x47};
|
||||
u8 FIRMblock[4] = {0x00, 0x20, 0xC0, 0x46};
|
||||
u8 emuInstr[5] = {0xA5, 0x01, 0x08, 0x30, 0xA5};
|
||||
*process9Size = (off->ncch.exeFsSize - 1) * 0x200;
|
||||
*process9MemAddr = off->exHeader.systemControlInfo.textCodeSet.address;
|
||||
|
||||
/**************************************************
|
||||
* Functions
|
||||
**************************************************/
|
||||
return (u8 *)off + (off->ncch.exeFsOffset + 1) * 0x200;
|
||||
}
|
||||
|
||||
void getSignatures(void *pos, u32 size, u32 *off, u32 *off2){
|
||||
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0xB0, 0x9C, 0xE5};
|
||||
*arm11ExceptionsPage = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(*arm11ExceptionsPage == NULL) error("Failed to get Kernel11 data.");
|
||||
|
||||
u32 *arm11SvcTable;
|
||||
|
||||
*arm11ExceptionsPage -= 0xB;
|
||||
u32 svcOffset = (-(((*arm11ExceptionsPage)[2] & 0xFFFFFF) << 2) & (0xFFFFFF << 2)) - 8; //Branch offset + 8 for prefetch
|
||||
u32 pointedInstructionVA = 0xFFFF0008 - svcOffset;
|
||||
*baseK11VA = pointedInstructionVA & 0xFFFF0000; //This assumes that the pointed instruction has an offset < 0x10000, iirc that's always the case
|
||||
arm11SvcTable = *arm11SvcHandler = (u32 *)(pos + *(u32 *)(pos + pointedInstructionVA - *baseK11VA + 8) - *baseK11VA); //SVC handler address
|
||||
while(*arm11SvcTable) arm11SvcTable++; //Look for SVC0 (NULL)
|
||||
|
||||
u32 *freeSpace;
|
||||
for(freeSpace = *arm11ExceptionsPage; freeSpace < *arm11ExceptionsPage + 0x400 && *freeSpace != 0xFFFFFFFF; freeSpace++);
|
||||
*freeK11Space = (u8 *) freeSpace;
|
||||
|
||||
return arm11SvcTable;
|
||||
}
|
||||
|
||||
void installMMUHook(u8 *pos, u32 size, u8 **freeK11Space)
|
||||
{
|
||||
const u8 pattern[] = {0x0E, 0x32, 0xA0, 0xE3, 0x02, 0xC2, 0xA0, 0xE3};
|
||||
|
||||
u32 *off = (u32 *)memsearch(pos, pattern, size, 8);
|
||||
|
||||
memcpy(*freeK11Space, mmuHook_bin, mmuHook_bin_size);
|
||||
*off = MAKE_BRANCH_LINK(off, *freeK11Space);
|
||||
|
||||
(*freeK11Space) += mmuHook_bin_size;
|
||||
}
|
||||
|
||||
void installK11MainHook(u8 *pos, u32 size, bool isSafeMode, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0x00, 0xA0, 0xE1, 0x03, 0xF0, 0x20, 0xE3, 0xFD, 0xFF, 0xFF, 0xEA};
|
||||
|
||||
u32 *off = (u32 *)memsearch(pos, pattern, size, 12);
|
||||
// look for cpsie i and place our function call in the nop 2 instructions before
|
||||
while(*off != 0xF1080080) off--;
|
||||
off -= 2;
|
||||
|
||||
memcpy(*freeK11Space, k11MainHook_bin, k11MainHook_bin_size);
|
||||
|
||||
u32 relocBase = 0xFFFF0000 + (*freeK11Space - (u8 *)arm11ExceptionsPage);
|
||||
*off = MAKE_BRANCH_LINK(baseK11VA + ((u8 *)off - pos), relocBase);
|
||||
|
||||
off = (u32 *)(pos + (arm11SvcTable[0x50] - baseK11VA)); //svcBindInterrupt
|
||||
while(off[0] != 0xE1A05000 || off[1] != 0xE2100102 || off[2] != 0x5A00000B) off++;
|
||||
off--;
|
||||
|
||||
signed int offset = (*off & 0xFFFFFF) << 2;
|
||||
offset = offset << 6 >> 6; // sign extend
|
||||
offset += 8;
|
||||
|
||||
u32 InterruptManager_mapInterrupt = baseK11VA + ((u8 *)off - pos) + offset;
|
||||
u32 interruptManager = *(u32 *)(off - 4 + (*(off - 6) & 0xFFF) / 4);
|
||||
|
||||
off = (u32 *)memsearch(*freeK11Space, "bind", k11MainHook_bin_size, 4);
|
||||
|
||||
*off++ = InterruptManager_mapInterrupt;
|
||||
|
||||
// Relocate stuff
|
||||
*off++ += relocBase;
|
||||
*off++ += relocBase;
|
||||
off++;
|
||||
*off++ = interruptManager;
|
||||
|
||||
off += 10;
|
||||
|
||||
struct CfwInfo
|
||||
{
|
||||
char magic[4];
|
||||
|
||||
u8 versionMajor;
|
||||
u8 versionMinor;
|
||||
u8 versionBuild;
|
||||
u8 flags;
|
||||
|
||||
u32 commitHash;
|
||||
|
||||
u32 config;
|
||||
} __attribute__((packed)) *info = (struct CfwInfo *)off;
|
||||
|
||||
const char *rev = REVISION;
|
||||
memcpy(&info->magic, "LUMA", 4);
|
||||
info->commitHash = COMMIT_HASH;
|
||||
info->config = configData.config;
|
||||
info->versionMajor = (u8)(rev[1] - '0');
|
||||
info->versionMinor = (u8)(rev[3] - '0');
|
||||
|
||||
if(rev[4] == '.')
|
||||
info->versionBuild = (u8)(rev[5] - '0');
|
||||
|
||||
const char *revpos;
|
||||
for(revpos = rev + 4; *revpos != 0 && *revpos != '-'; revpos++);
|
||||
bool isRelease = *revpos != '-';
|
||||
|
||||
if(isRelease) info->flags = 1;
|
||||
if(ISN3DS) info->flags |= 1 << 4;
|
||||
if(isSafeMode) info->flags |= 1 << 5;
|
||||
if(isSdMode) info->flags |= 1 << 6;
|
||||
|
||||
(*freeK11Space) += k11MainHook_bin_size;
|
||||
}
|
||||
|
||||
void installSvcConnectToPortInitHook(u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space)
|
||||
{
|
||||
u32 addr = 0xFFFF0000 + (u32)*freeK11Space - (u32)arm11ExceptionsPage;
|
||||
u32 svcSleepThreadAddr = arm11SvcTable[0x0A], svcConnectToPortAddr = arm11SvcTable[0x2D];
|
||||
|
||||
arm11SvcTable[0x2D] = addr;
|
||||
memcpy(*freeK11Space, svcConnectToPortInitHook_bin, svcConnectToPortInitHook_bin_size);
|
||||
|
||||
u32 *off = (u32 *)memsearch(*freeK11Space, "orig", svcConnectToPortInitHook_bin_size, 4);
|
||||
off[0] = svcConnectToPortAddr;
|
||||
off[1] = svcSleepThreadAddr;
|
||||
|
||||
(*freeK11Space) += svcConnectToPortInitHook_bin_size;
|
||||
}
|
||||
|
||||
|
||||
void installSvcCustomBackdoor(u32 *arm11SvcTable, u8 **freeK11Space, u32 *arm11ExceptionsPage)
|
||||
{
|
||||
memcpy(*freeK11Space, svcCustomBackdoor_bin, svcCustomBackdoor_bin_size);
|
||||
*((u32 *)*freeK11Space + 1) = arm11SvcTable[0x2F]; // temporary location
|
||||
arm11SvcTable[0x2F] = 0xFFFF0000 + *freeK11Space - (u8 *)arm11ExceptionsPage;
|
||||
(*freeK11Space) += svcCustomBackdoor_bin_size;
|
||||
}
|
||||
|
||||
u32 patchSignatureChecks(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for signature checks
|
||||
unsigned char pattern[] = {0xC0, 0x1C, 0x76, 0xE7};
|
||||
unsigned char pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
||||
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
|
||||
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
|
||||
|
||||
*off = (u32)memsearch(pos, pattern, size, 4);
|
||||
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
|
||||
|
||||
if(off == NULL || temp == NULL) return 1;
|
||||
|
||||
u16 *off2 = (u16 *)(temp - 1);
|
||||
*off = off2[0] = 0x2000;
|
||||
off2[1] = 0x4770;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void getReboot(void *pos, u32 size, u32 *off){
|
||||
//Look for FIRM reboot code
|
||||
unsigned char pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
|
||||
u32 patchOldSignatureChecks(u8 *pos, u32 size)
|
||||
{
|
||||
// Look for signature checks
|
||||
const u8 pattern[] = {0xC0, 0x1C, 0xBD, 0xE7},
|
||||
pattern2[] = {0xB5, 0x23, 0x4E, 0x0C};
|
||||
|
||||
*off = (u32)memsearch(pos, pattern, size, 4) - 0x10;
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
u8 *temp = memsearch(pos, pattern2, size, sizeof(pattern2));
|
||||
|
||||
if(off == NULL || temp == NULL) return 1;
|
||||
|
||||
u16 *off2 = (u16 *)(temp - 1);
|
||||
*off = off2[0] = 0x2000;
|
||||
off2[1] = 0x4770;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void getfOpen(void *pos, u32 size, u32 *off){
|
||||
//Calculate fOpen
|
||||
u32 p9addr = *(u32*)(memsearch(pos, "ess9", size, 4) + 0xC);
|
||||
u32 p9off = (u32)(memsearch(pos, "code", size, 4) + 0x1FF);
|
||||
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr)
|
||||
{
|
||||
//Look for firmlaunch code
|
||||
const u8 pattern[] = {0xE2, 0x20, 0x20, 0x90};
|
||||
|
||||
unsigned char pattern[] = {0xB0, 0x04, 0x98, 0x0D};
|
||||
u32 pathLen;
|
||||
for(pathLen = 0; pathLen < 41 && launchedPath[pathLen] != 0; pathLen++);
|
||||
|
||||
*off = (u32)memsearch(pos, pattern, size, 4) - 2 - p9off + p9addr;
|
||||
if(launchedPath[pathLen] != 0) return 1;
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off -= 0x13;
|
||||
|
||||
//Firmlaunch function offset - offset in BLX opcode (A4-16 - ARM DDI 0100E) + 1
|
||||
u32 fOpenOffset = (u32)(off + 9 - (-((*(u32 *)off & 0x00FFFFFF) << 2) & (0xFFFFFF << 2)) - pos + process9MemAddr);
|
||||
|
||||
//Copy firmlaunch code
|
||||
memcpy(off, reboot_bin, reboot_bin_size);
|
||||
|
||||
//Put the fOpen offset in the right location
|
||||
u32 *pos_fopen = (u32 *)memsearch(off, "OPEN", reboot_bin_size, 4);
|
||||
*pos_fopen = fOpenOffset;
|
||||
|
||||
u16 *fname = (u16 *)memsearch(off, "FILE", reboot_bin_size, 8);
|
||||
memcpy(fname, launchedPath, 2 * (1 + pathLen));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void getFIRMWrite(void *pos, u32 size, u32 *off){
|
||||
u32 patchFirmWrites(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for FIRM writing code
|
||||
void *firmwrite = memsearch(pos, "exe:", size, 4);
|
||||
unsigned char pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
||||
u8 *off = memsearch(pos, "exe:", size, 4);
|
||||
|
||||
*off = (u32)memsearch(firmwrite - 0x100, pattern, 0x100, 4);
|
||||
}
|
||||
if(off == NULL) return 1;
|
||||
|
||||
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
|
||||
|
||||
u16 *off2 = (u16 *)memsearch(off - 0x100, pattern, 0x100, sizeof(pattern));
|
||||
|
||||
if(off2 == NULL) return 1;
|
||||
|
||||
off2[0] = 0x2000;
|
||||
off2[1] = 0x46C0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchOldFirmWrites(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for FIRM writing code
|
||||
const u8 pattern[] = {0x04, 0x1E, 0x1D, 0xDB};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[0] = 0x2400;
|
||||
off[1] = 0xE01D;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion)
|
||||
{
|
||||
const u8 pattern[] = {0xFF, 0x00, 0x00, 0x02};
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return firmVersion == 0xFFFFFFFF ? 0 : 1;
|
||||
|
||||
off++;
|
||||
|
||||
//Zero out the first TitleID in the list
|
||||
memset32(off, 0, 8);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x28, 0x2A, 0xD0, 0x08};
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
u16 *off = (u16 *)(temp - 1);
|
||||
*off = 0x2001; //mov r0, #1
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x07, 0xD1, 0x28, 0x7A};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off--;
|
||||
*off = 0x2001; //mov r0, #1
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchCheckForDevCommonKey(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x03, 0x7C, 0x28, 0x00};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
*off = 0x2301; //mov r3, #1
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *pos, u32 size)
|
||||
{
|
||||
const u8 moduleLoadingPattern[] = {0xE2, 0x05, 0x00, 0x57},
|
||||
modulePidPattern[] = {0x06, 0xA0, 0xE1, 0xF2}; //GetSystemInfo
|
||||
|
||||
u8 *off = memsearch(pos, moduleLoadingPattern, size, 4);
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[1]++;
|
||||
|
||||
u32 *off32;
|
||||
for(off32 = (u32 *)(off - 3); *off32 != 0xE59F0000; off32++);
|
||||
off32 += 2;
|
||||
off32[1] = off32[0] + modulesSize;
|
||||
for(; *off32 != section0size; off32++);
|
||||
*off32 += ((modulesSize + 0x1FF) >> 9) << 9;
|
||||
|
||||
off = memsearch(pos, modulePidPattern, size, 4);
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[0xB] = 6;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x80, 0xE5, 0x40, 0x1C};
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
u32 *off = (u32 *)(temp - 0xA);
|
||||
|
||||
for(u32 r0 = 0x08000000; *off != 0xE3A01040; off++) //Until mov r1, #0x40
|
||||
{
|
||||
//Discard everything that's not str rX, [r0, #imm](!)
|
||||
if((*off & 0xFE5F0000) != 0xE4000000) continue;
|
||||
|
||||
u32 rD = (*off >> 12) & 0xF,
|
||||
offset = (*off & 0xFFF) * ((((*off >> 23) & 1) == 0) ? -1 : 1);
|
||||
bool writeback = ((*off >> 21) & 1) != 0,
|
||||
pre = ((*off >> 24) & 1) != 0;
|
||||
|
||||
u32 addr = r0 + ((pre || !writeback) ? offset : 0);
|
||||
if((addr & 7) != 0 && addr != 0x08000014 && addr != 0x08000004) *off = 0xE1A00000; //nop
|
||||
else *off = 0xE5800000 | (rD << 12) | (addr & 0xFFF); //Preserve IRQ and SVC handlers
|
||||
|
||||
if(!pre) addr += offset;
|
||||
if(writeback) r0 = addr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address)
|
||||
{
|
||||
//Stub svcBreak with "bkpt 65535" so we can debug the panic
|
||||
|
||||
//Look for the svc handler
|
||||
const u8 pattern[] = {0x00, 0xE0, 0x4F, 0xE1}; //mrs lr, spsr
|
||||
|
||||
u32 *arm9SvcTable = (u32 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(arm9SvcTable == NULL) return 1;
|
||||
|
||||
while(*arm9SvcTable != 0) arm9SvcTable++; //Look for SVC0 (NULL)
|
||||
|
||||
u32 *addr = (u32 *)(pos + arm9SvcTable[0x3C] - kernel9Address);
|
||||
*addr = 0xE12FFF7F;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchKernel9Panic(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0xFF, 0xEA, 0x04, 0xD0};
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
u32 *off = (u32 *)(temp - 0x12);
|
||||
*off = 0xE12FFF7E;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchP9AccessChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0x08, 0x49, 0x68};
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
u16 *off = (u16 *)(temp - 3);
|
||||
off[0] = 0x2001; //mov r0, #1
|
||||
off[1] = 0x4770; //bx lr
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchUnitInfoValueSet(u8 *pos, u32 size)
|
||||
{
|
||||
//Look for UNITINFO value being set during kernel sync
|
||||
const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13};
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[0] = ISDEVUNIT ? 0 : 1;
|
||||
off[3] = 0xE3;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchLgySignatureChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x47, 0xC1, 0x17, 0x49};
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
u16 *off = (u16 *)(temp + 1);
|
||||
off[0] = 0x2000;
|
||||
off[1] = 0xB04E;
|
||||
off[2] = 0xBD70;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x20, 0xF6, 0xE7, 0x7F};
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL) return 1;
|
||||
|
||||
u16 *off = (u16 *)(temp - 1);
|
||||
*off = 0x2001; //mov r0, #1
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0xC0, 0x30, 0x06, 0xF0};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[1] = 0x2000;
|
||||
off[2] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlWhitelistChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x22, 0x00, 0x20, 0x30};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[2] = 0x2000;
|
||||
off[3] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion)
|
||||
{
|
||||
const u8 pattern[] = {0x25, 0x20, 0x00, 0x0E};
|
||||
|
||||
u8 *temp = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(temp == NULL)
|
||||
{
|
||||
if(firmVersion == 0xFFFFFFFF) return patchOldTwlFlashcartChecks(pos, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
u16 *off = (u16 *)(temp + 3);
|
||||
off[0] = off[6] = off[0xC] = 0x2001; //mov r0, #1
|
||||
off[1] = off[7] = off[0xD] = 0; //nop
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x06, 0xF0, 0xA0, 0xFD};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[0] = off[6] = 0x2001; //mov r0, #1
|
||||
off[1] = off[7] = 0; //nop
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchTwlShaHashChecks(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x10, 0xB5, 0x14, 0x22};
|
||||
|
||||
u16 *off = (u16 *)memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[0] = 0x2001; //mov r0, #1
|
||||
off[1] = 0x4770;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 patchAgbBootSplash(u8 *pos, u32 size)
|
||||
{
|
||||
const u8 pattern[] = {0x00, 0x00, 0x01, 0xEF};
|
||||
|
||||
u8 *off = memsearch(pos, pattern, size, sizeof(pattern));
|
||||
|
||||
if(off == NULL) return 1;
|
||||
|
||||
off[2] = 0x26;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,70 @@
|
||||
/*
|
||||
* patches.h
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
#ifndef PATCHES_INC
|
||||
#define PATCHES_INC
|
||||
|
||||
/*
|
||||
* Signature patches by an unknown author
|
||||
* Signature patches for old FIRMs by SciresM
|
||||
* firmlaunches patching code originally by delebile
|
||||
* FIRM partition writes patches by delebile
|
||||
* Idea for svcBreak patches from yellows8 and others on #3dsdev
|
||||
* TWL_FIRM patches by Steveice10 and others
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
/**************************************************
|
||||
* Patches
|
||||
**************************************************/
|
||||
u8 mpu[0x2C];
|
||||
u8 nandRedir[0x08];
|
||||
u8 sigPat1[2];
|
||||
u8 sigPat2[4];
|
||||
u8 FIRMblock[4];
|
||||
u8 emuInstr[5];
|
||||
extern CfgData configData;
|
||||
|
||||
/**************************************************
|
||||
* Functions
|
||||
**************************************************/
|
||||
void getSignatures(void *pos, u32 size, u32 *off, u32 *off2);
|
||||
void getReboot(void *pos, u32 size, u32 *off);
|
||||
void getfOpen(void *pos, u32 size, u32 *off);
|
||||
void getFIRMWrite(void *pos, u32 size, u32 *off);
|
||||
|
||||
#endif
|
||||
u8 *getProcess9Info(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
|
||||
u32 *getKernel11Info(u8 *pos, u32 size, u32 *baseK11VA, u8 **freeK11Space, u32 **arm11SvcHandler, u32 **arm11ExceptionsPage);
|
||||
void installMMUHook(u8 *pos, u32 size, u8 **freeK11Space);
|
||||
void installK11MainHook(u8 *pos, u32 size, bool isSafeMode, u32 baseK11VA, u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space);
|
||||
void installSvcConnectToPortInitHook(u32 *arm11SvcTable, u32 *arm11ExceptionsPage, u8 **freeK11Space);
|
||||
void installSvcCustomBackdoor(u32 *arm11SvcTable, u8 **freeK11Space, u32 *arm11ExceptionsPage);
|
||||
u32 patchSignatureChecks(u8 *pos, u32 size);
|
||||
u32 patchOldSignatureChecks(u8 *pos, u32 size);
|
||||
u32 patchFirmlaunches(u8 *pos, u32 size, u32 process9MemAddr);
|
||||
u32 patchFirmWrites(u8 *pos, u32 size);
|
||||
u32 patchOldFirmWrites(u8 *pos, u32 size);
|
||||
u32 patchTitleInstallMinVersionChecks(u8 *pos, u32 size, u32 firmVersion);
|
||||
u32 patchZeroKeyNcchEncryptionCheck(u8 *pos, u32 size);
|
||||
u32 patchNandNcchEncryptionCheck(u8 *pos, u32 size);
|
||||
u32 patchCheckForDevCommonKey(u8 *pos, u32 size);
|
||||
u32 patchK11ModuleLoading(u32 section0size, u32 modulesSize, u8 *startPos, u32 size);
|
||||
u32 patchArm9ExceptionHandlersInstall(u8 *pos, u32 size);
|
||||
u32 patchSvcBreak9(u8 *pos, u32 size, u32 kernel9Address);
|
||||
u32 patchKernel9Panic(u8 *pos, u32 size);
|
||||
u32 patchP9AccessChecks(u8 *pos, u32 size);
|
||||
u32 patchUnitInfoValueSet(u8 *pos, u32 size);
|
||||
u32 patchLgySignatureChecks(u8 *pos, u32 size);
|
||||
u32 patchTwlInvalidSignatureChecks(u8 *pos, u32 size);
|
||||
u32 patchTwlNintendoLogoChecks(u8 *pos, u32 size);
|
||||
u32 patchTwlWhitelistChecks(u8 *pos, u32 size);
|
||||
u32 patchTwlFlashcartChecks(u8 *pos, u32 size, u32 firmVersion);
|
||||
u32 patchOldTwlFlashcartChecks(u8 *pos, u32 size);
|
||||
u32 patchTwlShaHashChecks(u8 *pos, u32 size);
|
||||
u32 patchAgbBootSplash(u8 *pos, u32 size);
|
||||
|
||||
222
source/pin.c
Normal file
222
source/pin.c
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Code originally by reworks
|
||||
*/
|
||||
|
||||
#include "draw.h"
|
||||
#include "config.h"
|
||||
#include "screen.h"
|
||||
#include "utils.h"
|
||||
#include "memory.h"
|
||||
#include "buttons.h"
|
||||
#include "fs.h"
|
||||
#include "pin.h"
|
||||
#include "crypto.h"
|
||||
|
||||
static char pinKeyToLetter(u32 pressed)
|
||||
{
|
||||
const char keys[] = "AB--RLUD--XY";
|
||||
|
||||
u32 i;
|
||||
for(i = 31; pressed > 1; i--) pressed /= 2;
|
||||
|
||||
return keys[31 - i];
|
||||
}
|
||||
|
||||
void newPin(bool allowSkipping, u32 pinMode)
|
||||
{
|
||||
clearScreens(false);
|
||||
|
||||
u8 length = 4 + 2 * (pinMode - 1);
|
||||
|
||||
drawString(true, 10, 10, COLOR_TITLE, "Enter a new PIN using ABXY and the DPad");
|
||||
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, allowSkipping ? "Press START to skip, SELECT to reset" : "Press SELECT to reset");
|
||||
|
||||
drawFormattedString(true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE, "PIN (%u digits): ", length);
|
||||
|
||||
//Pad to AES block length with zeroes
|
||||
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
bool reset = false;
|
||||
u8 cnt = 0;
|
||||
|
||||
while(cnt < length)
|
||||
{
|
||||
if(reset)
|
||||
{
|
||||
for(u32 i = 0; i < cnt; i++)
|
||||
drawCharacter(true, 10 + (16 + 2 * i) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_BLACK, (char)enteredPassword[i]);
|
||||
|
||||
cnt = 0;
|
||||
reset = false;
|
||||
}
|
||||
|
||||
u32 pressed;
|
||||
do
|
||||
{
|
||||
pressed = waitInput(false);
|
||||
}
|
||||
while(!(pressed & PIN_BUTTONS));
|
||||
|
||||
pressed &= PIN_BUTTONS;
|
||||
if(!allowSkipping) pressed &= ~BUTTON_START;
|
||||
|
||||
if(pressed & BUTTON_START) return;
|
||||
|
||||
if(pressed & BUTTON_SELECT)
|
||||
{
|
||||
reset = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!pressed) continue;
|
||||
|
||||
//Add character to password
|
||||
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
||||
|
||||
//Visualize character on screen
|
||||
drawCharacter(true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE, enteredPassword[cnt]);
|
||||
|
||||
cnt++;
|
||||
}
|
||||
|
||||
PinData pin;
|
||||
|
||||
memcpy(pin.magic, "PINF", 4);
|
||||
pin.formatVersionMajor = PIN_VERSIONMAJOR;
|
||||
pin.formatVersionMinor = PIN_VERSIONMINOR;
|
||||
|
||||
__attribute__((aligned(4))) u8 tmp[SHA_256_HASH_SIZE],
|
||||
lengthBlock[AES_BLOCK_SIZE] = {0};
|
||||
lengthBlock[0] = length;
|
||||
|
||||
computePinHash(tmp, lengthBlock);
|
||||
memcpy(pin.lengthHash, tmp, sizeof(tmp));
|
||||
|
||||
computePinHash(tmp, enteredPassword);
|
||||
memcpy(pin.hash, tmp, sizeof(tmp));
|
||||
|
||||
if(!fileWrite(&pin, PIN_FILE, sizeof(PinData)))
|
||||
error("Error writing the PIN file");
|
||||
}
|
||||
|
||||
bool verifyPin(u32 pinMode)
|
||||
{
|
||||
PinData pin;
|
||||
|
||||
if(fileRead(&pin, PIN_FILE, sizeof(PinData)) != sizeof(PinData) ||
|
||||
memcmp(pin.magic, "PINF", 4) != 0 ||
|
||||
pin.formatVersionMajor != PIN_VERSIONMAJOR ||
|
||||
pin.formatVersionMinor != PIN_VERSIONMINOR)
|
||||
return false;
|
||||
|
||||
__attribute__((aligned(4))) u8 tmp[SHA_256_HASH_SIZE],
|
||||
lengthBlock[AES_BLOCK_SIZE] = {0};
|
||||
lengthBlock[0] = 4 + 2 * (pinMode - 1);
|
||||
|
||||
computePinHash(tmp, lengthBlock);
|
||||
|
||||
//Test vector verification (check if SD card has been used on another console or PIN length changed)
|
||||
if(memcmp(pin.lengthHash, tmp, sizeof(tmp)) != 0) return false;
|
||||
|
||||
initScreens();
|
||||
|
||||
drawString(true, 10, 10, COLOR_TITLE, "Enter the PIN using ABXY and the DPad to proceed");
|
||||
drawString(true, 10, 10 + SPACING_Y, COLOR_TITLE, "Press START to shutdown, SELECT to clear");
|
||||
|
||||
drawFormattedString(true, 10, 10 + 3 * SPACING_Y, COLOR_WHITE, "PIN (%u digits): ", lengthBlock[0]);
|
||||
|
||||
const char *messageFile = "pinmessage.txt";
|
||||
char message[801];
|
||||
|
||||
u32 messageSize = fileRead(message, messageFile, sizeof(message) - 1);
|
||||
|
||||
if(messageSize != 0)
|
||||
{
|
||||
message[messageSize] = 0;
|
||||
drawString(false, 10, 10, COLOR_WHITE, message);
|
||||
}
|
||||
|
||||
//Pad to AES block length with zeroes
|
||||
__attribute__((aligned(4))) u8 enteredPassword[AES_BLOCK_SIZE] = {0};
|
||||
|
||||
bool unlock = false,
|
||||
reset = false;
|
||||
u8 cnt = 0;
|
||||
|
||||
while(!unlock)
|
||||
{
|
||||
if(reset)
|
||||
{
|
||||
for(u32 i = 0; i < cnt; i++)
|
||||
drawCharacter(true, 10 + (16 + 2 * i) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_BLACK, '*');
|
||||
|
||||
cnt = 0;
|
||||
reset = false;
|
||||
}
|
||||
|
||||
u32 pressed;
|
||||
do
|
||||
{
|
||||
pressed = waitInput(false);
|
||||
}
|
||||
while(!(pressed & PIN_BUTTONS));
|
||||
|
||||
if(pressed & BUTTON_START) mcuPowerOff();
|
||||
|
||||
pressed &= PIN_BUTTONS;
|
||||
|
||||
if(pressed & BUTTON_SELECT)
|
||||
{
|
||||
reset = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!pressed) continue;
|
||||
|
||||
//Add character to password
|
||||
enteredPassword[cnt] = (u8)pinKeyToLetter(pressed);
|
||||
|
||||
//Visualize character on screen
|
||||
drawCharacter(true, 10 + (16 + 2 * cnt) * SPACING_X, 10 + 3 * SPACING_Y, COLOR_WHITE, '*');
|
||||
|
||||
if(++cnt < lengthBlock[0]) continue;
|
||||
|
||||
computePinHash(tmp, enteredPassword);
|
||||
unlock = memcmp(pin.hash, tmp, sizeof(tmp)) == 0;
|
||||
|
||||
if(!unlock)
|
||||
{
|
||||
reset = true;
|
||||
|
||||
drawString(true, 10, 10 + 5 * SPACING_Y, COLOR_RED, "Wrong PIN, try again");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
40
source/pin.h
Normal file
40
source/pin.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Code originally by reworks
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define PIN_FILE "pin.bin"
|
||||
#define PIN_VERSIONMAJOR 1
|
||||
#define PIN_VERSIONMINOR 3
|
||||
|
||||
void newPin(bool allowSkipping, u32 pinMode);
|
||||
bool verifyPin(u32 pinMode);
|
||||
122
source/screen.c
Normal file
122
source/screen.c
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others
|
||||
* Screen deinit code by tiniVi
|
||||
*/
|
||||
|
||||
#include "screen.h"
|
||||
#include "config.h"
|
||||
#include "memory.h"
|
||||
#include "i2c.h"
|
||||
#include "utils.h"
|
||||
|
||||
struct fb fbs[2];
|
||||
|
||||
static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
|
||||
|
||||
static volatile Arm11Operation *operation = (volatile Arm11Operation *)0x1FF80004;
|
||||
|
||||
static void invokeArm11Function(Arm11Operation op)
|
||||
{
|
||||
while(*operation != ARM11_READY);
|
||||
*operation = op;
|
||||
while(*operation != ARM11_READY);
|
||||
}
|
||||
|
||||
void prepareArm11ForFirmlaunch(void)
|
||||
{
|
||||
invokeArm11Function(PREPARE_ARM11_FOR_FIRMLAUNCH);
|
||||
}
|
||||
|
||||
void deinitScreens(void)
|
||||
{
|
||||
if(ARESCREENSINITIALIZED) invokeArm11Function(DEINIT_SCREENS);
|
||||
}
|
||||
|
||||
void updateBrightness(u32 brightnessIndex)
|
||||
{
|
||||
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[brightnessIndex];
|
||||
invokeArm11Function(UPDATE_BRIGHTNESS);
|
||||
}
|
||||
|
||||
void swapFramebuffers(bool isAlternate)
|
||||
{
|
||||
*(volatile bool *)ARM11_PARAMETERS_ADDRESS = isAlternate;
|
||||
invokeArm11Function(SWAP_FRAMEBUFFERS);
|
||||
}
|
||||
|
||||
void clearScreens(bool isAlternate)
|
||||
{
|
||||
struct fb *fbTemp = isAlternate ? &fbs[1] : &fbs[0];
|
||||
|
||||
*(volatile struct fb *)ARM11_PARAMETERS_ADDRESS = *fbTemp;
|
||||
invokeArm11Function(CLEAR_SCREENS);
|
||||
}
|
||||
|
||||
static void initScreensSequence(void)
|
||||
{
|
||||
*(vu32 *)ARM11_PARAMETERS_ADDRESS = brightness[MULTICONFIG(BRIGHTNESS)];
|
||||
invokeArm11Function(INIT_SCREENS_SEQUENCE);
|
||||
}
|
||||
|
||||
static void setupFramebuffers(void)
|
||||
{
|
||||
fbs[0].top_left = (u8 *)0x18300000;
|
||||
fbs[1].top_left = (u8 *)0x18400000;
|
||||
fbs[0].top_right = (u8 *)0x18300000;
|
||||
fbs[1].top_right = (u8 *)0x18400000;
|
||||
fbs[0].bottom = (u8 *)0x18346500;
|
||||
fbs[1].bottom = (u8 *)0x18446500;
|
||||
|
||||
memcpy((void *)ARM11_PARAMETERS_ADDRESS, fbs, sizeof(fbs));
|
||||
invokeArm11Function(SETUP_FRAMEBUFFERS);
|
||||
}
|
||||
|
||||
void initScreens(void)
|
||||
{
|
||||
static bool needToSetup = true;
|
||||
|
||||
if(needToSetup)
|
||||
{
|
||||
if(!ARESCREENSINITIALIZED)
|
||||
{
|
||||
initScreensSequence();
|
||||
|
||||
//Turn on backlight
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
|
||||
}
|
||||
else updateBrightness(MULTICONFIG(BRIGHTNESS));
|
||||
|
||||
setupFramebuffers();
|
||||
needToSetup = false;
|
||||
}
|
||||
|
||||
clearScreens(false);
|
||||
clearScreens(true);
|
||||
swapFramebuffers(false);
|
||||
}
|
||||
74
source/screen.h
Normal file
74
source/screen.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Screen init code by dark_samus, bil1s, Normmatt, delebile and others
|
||||
* Screen deinit code by tiniVi
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
|
||||
|
||||
#define ARESCREENSINITIALIZED (PDN_GPU_CNT != 1)
|
||||
|
||||
#define ARM11_PARAMETERS_ADDRESS 0x1FFFF000
|
||||
|
||||
#define SCREEN_TOP_WIDTH 400
|
||||
#define SCREEN_BOTTOM_WIDTH 320
|
||||
#define SCREEN_HEIGHT 240
|
||||
#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
|
||||
#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
|
||||
|
||||
struct fb {
|
||||
u8 *top_left;
|
||||
u8 *top_right;
|
||||
u8 *bottom;
|
||||
} __attribute__((packed));
|
||||
|
||||
typedef enum
|
||||
{
|
||||
INIT_SCREENS_SEQUENCE = 0,
|
||||
SETUP_FRAMEBUFFERS,
|
||||
CLEAR_SCREENS,
|
||||
SWAP_FRAMEBUFFERS,
|
||||
UPDATE_BRIGHTNESS,
|
||||
DEINIT_SCREENS,
|
||||
PREPARE_ARM11_FOR_FIRMLAUNCH,
|
||||
ARM11_READY,
|
||||
} Arm11Operation;
|
||||
|
||||
extern struct fb fbs[2];
|
||||
extern CfgData configData;
|
||||
|
||||
void prepareArm11ForFirmlaunch(void);
|
||||
void deinitScreens(void);
|
||||
void swapFramebuffers(bool isAlternate);
|
||||
void updateBrightness(u32 brightnessIndex);
|
||||
void clearScreens(bool isAlternate);
|
||||
void initScreens(void);
|
||||
128
source/start.s
128
source/start.s
@@ -1,27 +1,73 @@
|
||||
@ This file is part of Luma3DS
|
||||
@ Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
@
|
||||
@ This program is free software: you can redistribute it and/or modify
|
||||
@ it under the terms of the GNU General Public License as published by
|
||||
@ the Free Software Foundation, either version 3 of the License, or
|
||||
@ (at your option) any later version.
|
||||
@
|
||||
@ This program is distributed in the hope that it will be useful,
|
||||
@ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
@ GNU General Public License for more details.
|
||||
@
|
||||
@ You should have received a copy of the GNU General Public License
|
||||
@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
@
|
||||
@ Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
@ * Requiring preservation of specified reasonable legal notices or
|
||||
@ author attributions in that material or in the Appropriate Legal
|
||||
@ Notices displayed by works containing it.
|
||||
@ * Prohibiting misrepresentation of the origin of that material,
|
||||
@ or requiring that modified versions of such material be marked in
|
||||
@ reasonable ways as different from the original version.
|
||||
|
||||
.section .text.start
|
||||
.align 4
|
||||
.global _start
|
||||
_start:
|
||||
@ Disable interrupts and switch to supervisor mode (also clear flags)
|
||||
mov r4, #0x13
|
||||
orr r4, #0x1C0
|
||||
msr cpsr_cxsf, r4
|
||||
|
||||
mov r9, r0
|
||||
mov r10, r1
|
||||
mov r11, r2
|
||||
|
||||
@ Change the stack pointer
|
||||
mov sp, #0x27000000
|
||||
mov sp, #0x08100000
|
||||
|
||||
@ Disable caches / MPU
|
||||
mrc p15, 0, r4, c1, c0, 0 @ read control register
|
||||
bic r4, #(1<<16) @ - DTCM disable
|
||||
bic r4, #(1<<12) @ - instruction cache disable
|
||||
bic r4, #(1<<2) @ - data cache disable
|
||||
bic r4, #(1<<0) @ - MPU disable
|
||||
mcr p15, 0, r4, c1, c0, 0 @ write control register
|
||||
|
||||
@ Invalidate both caches, discarding any data they may contain,
|
||||
@ then drain the write buffer
|
||||
mov r4, #0
|
||||
mcr p15, 0, r4, c7, c5, 0
|
||||
mcr p15, 0, r4, c7, c6, 0
|
||||
mcr p15, 0, r4, c7, c10, 4
|
||||
|
||||
@ Give read/write access to all the memory regions
|
||||
ldr r5, =0x33333333
|
||||
mcr p15, 0, r5, c5, c0, 2 @ write data access
|
||||
mcr p15, 0, r5, c5, c0, 3 @ write instruction access
|
||||
ldr r0, =0x33333333
|
||||
mcr p15, 0, r0, c5, c0, 2 @ write data access
|
||||
mcr p15, 0, r0, c5, c0, 3 @ write instruction access
|
||||
|
||||
@ Sets MPU permissions and cache settings
|
||||
ldr r0, =0xFFFF001D @ ffff0000 32k
|
||||
ldr r1, =0x01FF801D @ 01ff8000 32k
|
||||
ldr r2, =0x08000027 @ 08000000 1M
|
||||
ldr r3, =0x10000021 @ 10000000 128k
|
||||
ldr r4, =0x10100025 @ 10100000 512k
|
||||
ldr r5, =0x20000035 @ 20000000 128M
|
||||
ldr r6, =0x1FF00027 @ 1FF00000 1M
|
||||
ldr r7, =0x1800002D @ 18000000 8M
|
||||
mov r10, #0x25
|
||||
mov r11, #0x25
|
||||
mov r12, #0x25
|
||||
@ Set MPU permissions and cache settings
|
||||
ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
|
||||
ldr r1, =0xFFF0001B @ fff00000 16k | dtcm
|
||||
ldr r2, =0x01FF801D @ 01ff8000 32k | itcm
|
||||
ldr r3, =0x08000027 @ 08000000 1M | arm9 mem
|
||||
ldr r4, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
|
||||
ldr r5, =0x20000035 @ 20000000 128M | fcram
|
||||
ldr r6, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
|
||||
ldr r7, =0x1800002D @ 18000000 8M | vram (+ 2MB)
|
||||
mov r8, #0x29
|
||||
mcr p15, 0, r0, c6, c0, 0
|
||||
mcr p15, 0, r1, c6, c1, 0
|
||||
mcr p15, 0, r2, c6, c2, 0
|
||||
@@ -30,29 +76,37 @@ _start:
|
||||
mcr p15, 0, r5, c6, c5, 0
|
||||
mcr p15, 0, r6, c6, c6, 0
|
||||
mcr p15, 0, r7, c6, c7, 0
|
||||
mcr p15, 0, r10, c3, c0, 0 @ Write bufferable 0, 2, 5
|
||||
mcr p15, 0, r11, c2, c0, 0 @ Data cacheable 0, 2, 5
|
||||
mcr p15, 0, r12, c2, c0, 1 @ Inst cacheable 0, 2, 5
|
||||
mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 3, 5
|
||||
mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 3, 5
|
||||
mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 3, 5
|
||||
|
||||
@ Enable caches
|
||||
mrc p15, 0, r4, c1, c0, 0 @ read control register
|
||||
orr r4, r4, #(1<<12) @ - instruction cache enable
|
||||
orr r4, r4, #(1<<2) @ - data cache enable
|
||||
orr r4, r4, #(1<<0) @ - mpu enable
|
||||
mcr p15, 0, r4, c1, c0, 0 @ write control register
|
||||
@ Set DTCM address and size to the default values
|
||||
ldr r1, =0xFFF0000A @ set DTCM address and size
|
||||
mcr p15, 0, r1, c9, c1, 0 @ set the dtcm Region Register
|
||||
|
||||
@ Flush caches
|
||||
mov r5, #0
|
||||
mcr p15, 0, r5, c7, c5, 0 @ flush I-cache
|
||||
mcr p15, 0, r5, c7, c6, 0 @ flush D-cache
|
||||
mcr p15, 0, r5, c7, c10, 4 @ drain write buffer
|
||||
@ Enable caches / MPU / ITCM
|
||||
mrc p15, 0, r0, c1, c0, 0 @ read control register
|
||||
orr r0, r0, #(1<<18) @ - ITCM enable
|
||||
orr r0, r0, #(1<<16) @ - DTCM enable
|
||||
orr r0, r0, #(1<<13) @ - alternate exception vectors enable
|
||||
orr r0, r0, #(1<<12) @ - instruction cache enable
|
||||
orr r0, r0, #(1<<2) @ - data cache enable
|
||||
orr r0, r0, #(1<<0) @ - MPU enable
|
||||
mcr p15, 0, r0, c1, c0, 0 @ write control register
|
||||
|
||||
@ Fixes mounting of SDMC
|
||||
ldr r0, =0x10000020
|
||||
mov r1, #0x340
|
||||
str r1, [r0]
|
||||
@ Fix mounting of SDMC
|
||||
ldr r0, =0x10000020
|
||||
mov r1, #0x340
|
||||
str r1, [r0]
|
||||
|
||||
bl main
|
||||
@ Clear BSS
|
||||
ldr r0, =__bss_start
|
||||
mov r1, #0
|
||||
ldr r2, =__bss_end
|
||||
sub r2, r0
|
||||
bl memset32
|
||||
|
||||
.die:
|
||||
b .die
|
||||
mov r0, r9
|
||||
mov r1, r10
|
||||
mov r2, r11
|
||||
b main
|
||||
|
||||
68
source/strings.c
Normal file
68
source/strings.c
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#include "strings.h"
|
||||
#include "memory.h"
|
||||
|
||||
u32 strlen(const char *string)
|
||||
{
|
||||
char *stringEnd = (char *)string;
|
||||
|
||||
while(*stringEnd != 0) stringEnd++;
|
||||
|
||||
return stringEnd - string;
|
||||
}
|
||||
|
||||
u32 strnlen(const char *string, u32 maxlen)
|
||||
{
|
||||
u32 size;
|
||||
|
||||
for(size = 0; size < maxlen && *string; string++, size++);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
u32 hexAtoi(const char *in, u32 digits)
|
||||
{
|
||||
u32 res = 0;
|
||||
char *tmp = (char *)in;
|
||||
|
||||
for(u32 i = 0; i < digits && *tmp != 0; tmp++, i++)
|
||||
res = (*tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0') + (res << 4);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 decAtoi(const char *in, u32 digits)
|
||||
{
|
||||
u32 res = 0;
|
||||
char *tmp = (char *)in;
|
||||
|
||||
for(u32 i = 0; i < digits && *tmp != 0; tmp++, i++)
|
||||
res = *tmp - '0' + res * 10;
|
||||
|
||||
return res;
|
||||
}
|
||||
34
source/strings.h
Normal file
34
source/strings.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
u32 strlen(const char *string);
|
||||
u32 strnlen(const char *string, u32 maxlen);
|
||||
u32 hexAtoi(const char *in, u32 digits);
|
||||
u32 decAtoi(const char *in, u32 digits);
|
||||
131
source/types.h
131
source/types.h
@@ -1,40 +1,119 @@
|
||||
/*
|
||||
* types.h
|
||||
* by Reisyukaku
|
||||
* Copyright (c) 2015 All Rights Reserved
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
#ifndef TYPES_INC
|
||||
#define TYPES_INC
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
//Common data types
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
||||
typedef volatile uint8_t vu8;
|
||||
typedef volatile uint16_t vu16;
|
||||
typedef volatile uint32_t vu32;
|
||||
typedef volatile uint64_t vu64;
|
||||
typedef volatile u8 vu8;
|
||||
typedef volatile u16 vu16;
|
||||
typedef volatile u32 vu32;
|
||||
typedef volatile u64 vu64;
|
||||
typedef int8_t s8;
|
||||
typedef int16_t s16;
|
||||
typedef int32_t s32;
|
||||
typedef int64_t s64;
|
||||
typedef volatile s8 vs8;
|
||||
typedef volatile s16 vs16;
|
||||
typedef volatile s32 vs32;
|
||||
typedef volatile s64 vs64;
|
||||
|
||||
//FIRM Header layout
|
||||
typedef struct firmSectionHeader {
|
||||
u32 offset;
|
||||
u8 *address;
|
||||
u32 size;
|
||||
u32 procType;
|
||||
u8 hash[0x20];
|
||||
} firmSectionHeader;
|
||||
#include "3dsheaders.h"
|
||||
|
||||
typedef struct firmHeader {
|
||||
u32 magic;
|
||||
u32 reserved1;
|
||||
u8 *arm11Entry;
|
||||
u8 *arm9Entry;
|
||||
u8 reserved2[0x30];
|
||||
firmSectionHeader section[4];
|
||||
} firmHeader;
|
||||
#define CFG_BOOTENV (*(vu32 *)0x10010000)
|
||||
#define CFG_UNITINFO (*(vu8 *)0x10010010)
|
||||
#define CFG_TWLUNITINFO (*(vu8 *)0x10010014)
|
||||
#define OTP_DEVCONSOLEID (*(vu64 *)0x10012000)
|
||||
#define OTP_TWLCONSOLEID (*(vu64 *)0x10012100)
|
||||
#define CFG11_SOCINFO (*(vu32 *)0x10140FFC)
|
||||
|
||||
#define ISN3DS (CFG11_SOCINFO & 2)
|
||||
#define ISDEVUNIT (CFG_UNITINFO != 0)
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
char magic[4];
|
||||
u16 formatVersionMajor, formatVersionMinor;
|
||||
|
||||
u32 config;
|
||||
} CfgData;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
char magic[4];
|
||||
u16 formatVersionMajor, formatVersionMinor;
|
||||
|
||||
u8 lengthHash[32];
|
||||
u8 hash[32];
|
||||
} PinData;
|
||||
|
||||
typedef struct __attribute__((packed))
|
||||
{
|
||||
u32 magic[2];
|
||||
u16 versionMinor, versionMajor;
|
||||
|
||||
u16 processor, core;
|
||||
u32 type;
|
||||
|
||||
u32 totalSize;
|
||||
u32 registerDumpSize;
|
||||
u32 codeDumpSize;
|
||||
u32 stackDumpSize;
|
||||
u32 additionalDataSize;
|
||||
} ExceptionDumpHeader;
|
||||
|
||||
typedef enum FirmwareSource
|
||||
{
|
||||
FIRMWARE_SYSNAND = 0,
|
||||
FIRMWARE_EMUNAND,
|
||||
FIRMWARE_EMUNAND2,
|
||||
FIRMWARE_EMUNAND3,
|
||||
FIRMWARE_EMUNAND4
|
||||
} FirmwareSource;
|
||||
|
||||
typedef enum FirmwareType
|
||||
{
|
||||
NATIVE_FIRM = 0,
|
||||
TWL_FIRM,
|
||||
AGB_FIRM,
|
||||
SAFE_FIRM,
|
||||
SYSUPDATER_FIRM,
|
||||
NATIVE_FIRM1X2X
|
||||
} FirmwareType;
|
||||
|
||||
extern bool isFirmlaunch,
|
||||
isSdMode;
|
||||
extern u16 launchedFirmTidLow[8];
|
||||
extern u16 launchedPath[41];
|
||||
|
||||
#endif
|
||||
146
source/utils.c
Normal file
146
source/utils.c
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* waitInput function based on code by d0k3 https://github.com/d0k3/Decrypt9WIP/blob/master/source/hid.c
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "i2c.h"
|
||||
#include "buttons.h"
|
||||
#include "screen.h"
|
||||
#include "draw.h"
|
||||
#include "cache.h"
|
||||
#include "fmt.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static void startChrono(void)
|
||||
{
|
||||
static bool isChronoStarted = false;
|
||||
|
||||
if(isChronoStarted) return;
|
||||
|
||||
REG_TIMER_CNT(0) = 0; //67MHz
|
||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
|
||||
|
||||
for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = 0;
|
||||
|
||||
REG_TIMER_CNT(0) = 0x80; //67MHz; enabled
|
||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
|
||||
|
||||
isChronoStarted = true;
|
||||
}
|
||||
|
||||
static u64 chrono(void)
|
||||
{
|
||||
u64 res = 0;
|
||||
for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
|
||||
|
||||
res /= (TICKS_PER_SEC / 1000);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
u32 waitInput(bool isMenu)
|
||||
{
|
||||
static u64 dPadDelay = 0ULL;
|
||||
u64 initialValue = 0ULL;
|
||||
u32 key,
|
||||
oldKey = HID_PAD;
|
||||
|
||||
if(isMenu)
|
||||
{
|
||||
dPadDelay = dPadDelay > 0ULL ? 87ULL : 143ULL;
|
||||
startChrono();
|
||||
initialValue = chrono();
|
||||
}
|
||||
|
||||
while(true)
|
||||
{
|
||||
key = HID_PAD;
|
||||
|
||||
if(!key)
|
||||
{
|
||||
if((i2cReadRegister(I2C_DEV_MCU, 0x10) & 1)== 1) mcuPowerOff();
|
||||
oldKey = 0;
|
||||
dPadDelay = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if(key == oldKey && (!isMenu || (!(key & DPAD_BUTTONS) || chrono() - initialValue < dPadDelay))) continue;
|
||||
|
||||
//Make sure the key is pressed
|
||||
u32 i;
|
||||
for(i = 0; i < 0x13000 && key == HID_PAD; i++);
|
||||
if(i == 0x13000) break;
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
void mcuPowerOff(void)
|
||||
{
|
||||
if(!isFirmlaunch && ARESCREENSINITIALIZED) clearScreens(false);
|
||||
|
||||
//Ensure that all memory transfers have completed and that the data cache has been flushed
|
||||
flushEntireDCache();
|
||||
|
||||
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
|
||||
while(true);
|
||||
}
|
||||
|
||||
void wait(u64 amount)
|
||||
{
|
||||
startChrono();
|
||||
|
||||
u64 initialValue = chrono();
|
||||
|
||||
while(chrono() - initialValue < amount);
|
||||
}
|
||||
|
||||
void error(const char *fmt, ...)
|
||||
{
|
||||
if(!isFirmlaunch)
|
||||
{
|
||||
char buf[DRAW_MAX_FORMATTED_STRING_SIZE + 1];
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
initScreens();
|
||||
|
||||
drawString(true, 10, 10, COLOR_RED, "An error has occurred:");
|
||||
u32 posY = drawString(true, 10, 30, COLOR_WHITE, buf);
|
||||
drawString(true, 10, posY + 2 * SPACING_Y, COLOR_WHITE, "Press any button to shutdown");
|
||||
|
||||
waitInput(false);
|
||||
}
|
||||
|
||||
mcuPowerOff();
|
||||
}
|
||||
42
source/utils.h
Normal file
42
source/utils.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2017 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
/*
|
||||
* waitInput function based on code by d0k3 https://github.com/d0k3/Decrypt9WIP/blob/master/source/hid.c
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
|
||||
#define TICKS_PER_SEC 67027964ULL
|
||||
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
|
||||
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
|
||||
|
||||
u32 waitInput(bool isMenu);
|
||||
void mcuPowerOff(void);
|
||||
void wait(u64 amount);
|
||||
void error(const char *fmt, ...);
|
||||
21
sysmodules/loader/LICENSE
Normal file
21
sysmodules/loader/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yifan Lu
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
71
sysmodules/loader/Makefile
Executable file
71
sysmodules/loader/Makefile
Executable file
@@ -0,0 +1,71 @@
|
||||
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
|
||||
|
||||
ifeq ($(strip $(DEVKITARM)),)
|
||||
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||
endif
|
||||
|
||||
include $(DEVKITARM)/3ds_rules
|
||||
|
||||
name := $(shell basename $(CURDIR))
|
||||
|
||||
dir_source := source
|
||||
dir_patches := patches
|
||||
dir_build := build
|
||||
dir_out := ../../$(dir_build)
|
||||
|
||||
LIBS := -lctru
|
||||
LIBDIRS := $(CTRULIB)
|
||||
LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
INCLUDE := $(foreach dir,$(LIBDIRS),-I$(dir)/include)
|
||||
|
||||
ASFLAGS := -mcpu=mpcore -mfloat-abi=hard
|
||||
CFLAGS := -Wall -Wextra $(ASFLAGS) -fno-builtin -std=c11 -O2 -flto -ffast-math $(INCLUDE) -DARM11 -D_3DS
|
||||
LDFLAGS := -specs=3dsx.specs $(ASFLAGS) -Wl,--section-start,.text=0x14000000
|
||||
|
||||
objects = $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
|
||||
$(call rwildcard, $(dir_source), *.s *.c))
|
||||
|
||||
bundled = $(dir_build)/romfsredir.bin.o
|
||||
|
||||
define bin2o
|
||||
bin2s $< | $(AS) -o $(@)
|
||||
endef
|
||||
|
||||
.PHONY: all
|
||||
all: $(dir_out)/$(name).cxi
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@rm -rf $(dir_build)
|
||||
|
||||
.PRECIOUS: $(dir_build)/%.bin
|
||||
|
||||
$(dir_out)/$(name).cxi: $(dir_build)/$(name).elf
|
||||
@makerom -f ncch -rsf loader.rsf -nocodepadding -o $@ -elf $<
|
||||
|
||||
$(dir_build)/$(name).elf: $(bundled) $(objects)
|
||||
$(LINK.o) $(OUTPUT_OPTION) $^ $(LIBPATHS) $(LIBS)
|
||||
|
||||
$(dir_build)/%.bin.o: $(dir_build)/%.bin
|
||||
@$(bin2o)
|
||||
|
||||
$(dir_build)/%.bin: $(dir_patches)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
@armips $<
|
||||
|
||||
$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
|
||||
|
||||
$(dir_build)/bundled.h: $(bundled)
|
||||
@$(foreach f, $(bundled),\
|
||||
echo "extern const u8" `(echo $(basename $(notdir $(f))) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> $@;\
|
||||
echo "extern const u32" `(echo $(basename $(notdir $(f)))| sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> $@;\
|
||||
)
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/bundled.h
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.c) $(OUTPUT_OPTION) $<
|
||||
|
||||
$(dir_build)/%.o: $(dir_source)/%.s
|
||||
@mkdir -p "$(@D)"
|
||||
$(COMPILE.s) $(OUTPUT_OPTION) $<
|
||||
30
sysmodules/loader/README.md
Normal file
30
sysmodules/loader/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
3DS Loader Replacement
|
||||
======================
|
||||
|
||||
This is an open source implementation of 3DS `loader` system module--with
|
||||
additional features. The current aim of the project is to provide a nice
|
||||
entry point for patching 3DS modules.
|
||||
|
||||
## Roadmap
|
||||
Right now, this can serve as an open-source replacement for the built in loader.
|
||||
There is additional support for patching any executable after it's loaded but
|
||||
before it starts. For example, you can patch `menu` to skip region checks and
|
||||
have region free game launching directly from the home menu. There is also
|
||||
support for SDMC reading (not found in original loader implementation) which
|
||||
means that patches can be loaded from the SD card. Ultimately, there would be
|
||||
a patch system that supports easy loading of patches from the SD card.
|
||||
|
||||
## Build
|
||||
You need a working 3DS build environment with a fairly recent copy of devkitARM,
|
||||
ctrulib, and makerom. If you see any errors in the build process, it's likely
|
||||
that you're using an older version.
|
||||
|
||||
Currently, there is no support for FIRM building, so you need to do some steps
|
||||
manually. First, you have to add padding to make sure the NCCH is of the right
|
||||
size to drop in as a replacement. A hacky way is
|
||||
[this patch](http://pastebin.com/nyKXLnNh) which adds junk data. Play around
|
||||
with the size value to get the NCCH to be the exact same size as the one
|
||||
found in your decrypted FIRM dump.
|
||||
|
||||
Once you have a NCCH of the right size, just replace it in your decrypted FIRM
|
||||
and find a way to launch it (for example with ReiNAND).
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user