aboutsummaryrefslogtreecommitdiff
path: root/frontend/3ds/libkhax/khaxinternal.h
blob: 5d83eab5a71eb5ddd47c88ecc47bb129fe989db2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
#pragma once

#define KHAX_DEBUG
//#define KHAX_DEBUG_DUMP_DATA

#ifdef KHAX_DEBUG
	#define KHAX_printf(...) printf(__VA_ARGS__), gspWaitForVBlank(), gfxFlushBuffers(), gfxSwapBuffers()
#else
	#define KHAX_printf static_cast<void>
#endif

// Shut up IntelliSense warnings when using MSVC as an IDE, even though MSVC will obviously never
// actually compile this program.
#ifdef _MSC_VER
	#undef ALIGN
	#define ALIGN(x) __declspec(align(x))
	#if _MSC_VER < 1900
		#define alignof __alignof
	#endif
	#define KHAX_ATTRIBUTE(...)
#else
	#define KHAX_ATTRIBUTE(...) __VA_ARGS__
#endif

#define KHAX_lengthof(...) (sizeof(__VA_ARGS__) / sizeof((__VA_ARGS__)[0]))

//------------------------------------------------------------------------------------------------
namespace KHAX
{
	//------------------------------------------------------------------------------------------------
	// This code uses offsetof illegally (i.e. on polymorphic classes).
	#pragma GCC diagnostic push
	#pragma GCC diagnostic ignored "-Winvalid-offsetof"

	//------------------------------------------------------------------------------------------------
	// General linked list node kernel object.
	struct KLinkedListNode
	{
		KLinkedListNode *next;
		KLinkedListNode *prev;
		void *data;
	};
	static_assert(sizeof(KLinkedListNode) == 0x00C, "KLinkedListNode isn't the expected size.");

	//------------------------------------------------------------------------------------------------
	// Base class of reference-counted kernel objects.
	class KAutoObject
	{
	public:
		u32 m_refCount;                                 // +004

	protected:
		virtual ~KAutoObject() {}
	};
	static_assert(sizeof(KAutoObject) == 0x008, "KAutoObject isn't the expected size.");
	static_assert(offsetof(KAutoObject, m_refCount) == 0x004, "KAutoObject isn't the expected layout.");

	//------------------------------------------------------------------------------------------------
	// Base class of synchronizable objects.
	class KSynchronizationObject : public KAutoObject
	{
	public:
		u32 m_threadSyncCount;                          // +008
		KLinkedListNode *m_threadSyncFirst;             // +00C
		KLinkedListNode *m_threadSyncLast;              // +010
	};
	static_assert(sizeof(KSynchronizationObject) == 0x014, "KSynchronizationObject isn't the expected size.");
	static_assert(offsetof(KSynchronizationObject, m_threadSyncCount) == 0x008,
		"KSynchronizationObject isn't the expected layout.");

	//------------------------------------------------------------------------------------------------
	struct KDebugThread;
	struct KThreadLocalPage;
	class KCodeSet;

	//------------------------------------------------------------------------------------------------
	// Unofficial name
	typedef u8 KSVCACL[0x80 / 8];

	//------------------------------------------------------------------------------------------------
	// ARM VFP register
	union KHAX_ATTRIBUTE(__attribute__((__aligned__(4))) __attribute__((__packed__))) VFPRegister
	{
		float m_single[2];
		double m_double;
	};
	static_assert(alignof(VFPRegister) == 0x004,
		"VFPRegister isn't the expected alignment.");
	static_assert(sizeof(VFPRegister) == 0x008,
		"VFPRegister isn't the expected size.");

	//------------------------------------------------------------------------------------------------
	// SVC-mode register save area.
	// http://3dbrew.org/wiki/Memory_layout#0xFF4XX000
	struct SVCRegisterState
	{
		u32 m_r4;                                       // +000
		u32 m_r5;                                       // +004
		u32 m_r6;                                       // +008
		u32 m_r7;                                       // +00C
		u32 m_r8;                                       // +010
		u32 m_r9;                                       // +014
		u32 m_sl;                                       // +018
		u32 m_fp;                                       // +01C
		u32 m_sp;                                       // +020
		u32 m_lr;                                       // +024
	};
	static_assert(sizeof(SVCRegisterState) == 0x028,
		"SVCRegisterState isn't the expected size.");

	//------------------------------------------------------------------------------------------------
	// SVC-mode thread state structure.  This is the last part of the per-
	// thread page allocated in 0xFF4XX000.
	// http://3dbrew.org/wiki/Memory_layout#0xFF4XX000
	struct SVCThreadArea
	{
		KSVCACL m_svcAccessControl;                     // +000
		u32 m_unknown010;                               // +010
		u32 m_unknown014;                               // +014
		SVCRegisterState m_svcRegisterState;            // +018
		VFPRegister m_vfpRegisters[16];                 // +040
		u32 m_unknown0C4;                               // +0C0
		u32 m_fpexc;                                    // +0C4
	};
	static_assert(offsetof(SVCThreadArea, m_svcRegisterState) == 0x018,
		"ThreadSVCArea isn't the expected layout.");
	static_assert(sizeof(SVCThreadArea) == 0x0C8,
		"ThreadSVCArea isn't the expected size.");

	//------------------------------------------------------------------------------------------------
	// Kernel's internal structure of a thread object.
	class KThread : public KSynchronizationObject
	{
	public:
		u32 m_unknown014;                               // +014
		u32 m_unknown018;                               // +018
		u32 m_unknown01C;                               // +01C
		u32 m_unknown020;                               // +020
		u32 m_unknown024;                               // +024
		u32 m_unknown028;                               // +028
		u32 m_unknown02C;                               // +02C
		u32 m_unknown030;                               // +030
		u32 m_unknown034;                               // +034
		KDebugThread *m_debugThread;                    // +038
		s32 m_threadPriority;                           // +03C
		void *m_waitingOnObject;                        // +040
		u32 m_unknown044;                               // +044
		KThread **m_schedulerUnknown048;                // +048
		void *m_arbitrationAddress;                     // +04C
		u32 m_unknown050;                               // +050
		u32 m_unknown054;                               // +054
		u32 m_unknown058;                               // +058
		KLinkedListNode *m_waitingOnList;               // +05C
		u32 m_unknownListCount;                         // +060
		KLinkedListNode *m_unknownListHead;             // +064
		KLinkedListNode *m_unknownListTail;             // +068
		s32 m_threadPriority2;                          // +06C
		s32 m_creatingProcessor;                        // +070
		u32 m_unknown074;                               // +074
		u32 m_unknown078;                               // +078
		u16 m_unknown07C;                               // +07C
		u8 m_threadType;                                // +07E
		u8 m_padding07F;                                // +07F
		void *m_process;                                // +080
		u32 m_threadID;                                 // +084
		SVCRegisterState *m_svcRegisterState;           // +088
		void *m_svcPageEnd;                             // +08C
		s32 m_idealProcessor;                           // +090
		void *m_tlsUserMode;                            // +094
		void *m_tlsKernelMode;                          // +098
		u32 m_unknown09C;                               // +09C
		KThread *m_prev;                                // +0A0
		KThread *m_next;                                // +0A4
		KThread **m_temporaryLinkedList;                // +0A8
		u32 m_unknown0AC;                               // +0B0
	};
	static_assert(sizeof(KThread) == 0x0B0,
		"KThread isn't the expected size.");
	static_assert(offsetof(KThread, m_svcRegisterState) == 0x088,
		"KThread isn't the expected layout.");

	//------------------------------------------------------------------------------------------------
	// Kernel's internal structure of a process object.
	// Version 1.0.0(?) - 7.2.0
	class KProcess_1_0_0_Old : public KSynchronizationObject
	{
	public:
		u32 m_unknown014;                               // +014
		u32 m_unknown018;                               // +018
		KThread *volatile m_interactingThread;          // +01C
		u16 m_unknown020;                               // +020
		u16 m_unknown022;                               // +022
		u32 m_unknown024;                               // +024
		u32 m_unknown028;                               // +028
		u32 m_memoryBlockCount;                         // +02C
		KLinkedListNode *m_memoryBlockFirst;            // +030
		KLinkedListNode *m_memoryBlockLast;             // +034
		u32 m_unknown038;                               // +038
		u32 m_unknown03C;                               // +03C
		void *m_translationTableBase;                   // +040
		u8 m_contextID;                                 // +044
		u32 m_unknown048;                               // +048
		u32 m_unknown04C;                               // +04C
		u32 m_mmuTableSize;                             // +050
		void *m_mmuTableAddress;                        // +054
		u32 m_threadContextPagesSize;                   // +058
		u32 m_threadLocalPageCount;                     // +05C
		KLinkedListNode *m_threadLocalPageFirst;        // +060
		KLinkedListNode *m_threadLocalPageLast;         // +064
		u32 m_unknown068;                               // +068
		s32 m_idealProcessor;                           // +06C
		u32 m_unknown070;                               // +070
		void *m_resourceLimits;                         // +074
		u8 m_unknown078;                                // +078
		u8 m_affinityMask;                              // +079
		u32 m_threadCount;                              // +07C
		KSVCACL m_svcAccessControl;                     // +080
		u32 m_interruptFlags[0x80 / 32];                // +090
		u32 m_kernelFlags;                              // +0A0
		u16 m_handleTableSize;                          // +0A4
		u16 m_kernelReleaseVersion;                     // +0A6
		KCodeSet *m_codeSet;                            // +0A8
		u32 m_processID;                                // +0AC
		u32 m_kernelFlags2;                             // +0B0
		u32 m_unknown0B4;                               // +0B4
		KThread *m_mainThread;                          // +0B8
		//...more...
	};
	static_assert(offsetof(KProcess_1_0_0_Old, m_svcAccessControl) == 0x080,
		"KProcess_1_0_0_Old isn't the expected layout.");

	//------------------------------------------------------------------------------------------------
	// Kernel's internal structure of a process object.
	// Old 3DS Version 8.0.0 - 9.5.0...
	class KProcess_8_0_0_Old : public KSynchronizationObject
	{
	public:
		u32 m_unknown014;                               // +014
		u32 m_unknown018;                               // +018
		KThread *volatile m_interactingThread;          // +01C
		u16 m_unknown020;                               // +020
		u16 m_unknown022;                               // +022
		u32 m_unknown024;                               // +024
		u32 m_unknown028;                               // +028
		u32 m_memoryBlockCount;                         // +02C
		KLinkedListNode *m_memoryBlockFirst;            // +030
		KLinkedListNode *m_memoryBlockLast;             // +034
		u32 m_unknown038;                               // +038
		u32 m_unknown03C;                               // +03C
		void *m_translationTableBase;                   // +040
		u8 m_contextID;                                 // +044
		u32 m_unknown048;                               // +048
		void *m_userVirtualMemoryEnd;                   // +04C
		void *m_userLinearVirtualBase;                  // +050
		u32 m_unknown054;                               // +054
		u32 m_mmuTableSize;                             // +058
		void *m_mmuTableAddress;                        // +05C
		u32 m_threadContextPagesSize;                   // +060
		u32 m_threadLocalPageCount;                     // +064
		KLinkedListNode *m_threadLocalPageFirst;        // +068
		KLinkedListNode *m_threadLocalPageLast;         // +06C
		u32 m_unknown070;                               // +070
		s32 m_idealProcessor;                           // +074
		u32 m_unknown078;                               // +078
		void *m_resourceLimits;                         // +07C
		u32 m_unknown080;                               // +080
		u32 m_threadCount;                              // +084
		u8 m_svcAccessControl[0x80 / 8];                // +088
		u32 m_interruptFlags[0x80 / 32];                // +098
		u32 m_kernelFlags;                              // +0A8
		u16 m_handleTableSize;                          // +0AC
		u16 m_kernelReleaseVersion;                     // +0AE
		KCodeSet *m_codeSet;                            // +0B0
		u32 m_processID;                                // +0B4
		u32 m_unknown0B8;                               // +0B8
		u32 m_unknown0BC;                               // +0BC
		KThread *m_mainThread;                          // +0C0
		//...more...
	};
	static_assert(offsetof(KProcess_8_0_0_Old, m_svcAccessControl) == 0x088,
		"KProcess_8_0_0_Old isn't the expected layout.");

	//------------------------------------------------------------------------------------------------
	// Kernel's internal structure of a process object.
	// New 3DS Version 8.0.0 - 9.5.0...
	class KProcess_8_0_0_New : public KSynchronizationObject
	{
	public:
		u32 m_unknown014;                               // +014
		u32 m_unknown018;                               // +018
		KThread *volatile m_interactingThread;          // +01C
		u16 m_unknown020;                               // +020
		u16 m_unknown022;                               // +022
		u32 m_unknown024;                               // +024
		u32 m_unknown028;                               // +028
		u32 m_unknown02C;                               // +02C new to New 3DS
		u32 m_unknown030;                               // +030 new to New 3DS
		u32 m_memoryBlockCount;                         // +034
		KLinkedListNode *m_memoryBlockFirst;            // +038
		KLinkedListNode *m_memoryBlockLast;             // +03C
		u32 m_unknown040;                               // +040
		u32 m_unknown044;                               // +044
		void *m_translationTableBase;                   // +048
		u8 m_contextID;                                 // +04C
		u32 m_unknown050;                               // +050
		void *m_userVirtualMemoryEnd;                   // +054
		void *m_userLinearVirtualBase;                  // +058
		u32 m_unknown05C;                               // +05C
		u32 m_mmuTableSize;                             // +060
		void *m_mmuTableAddress;                        // +064
		u32 m_threadContextPagesSize;                   // +068
		u32 m_threadLocalPageCount;                     // +06C
		KLinkedListNode *m_threadLocalPageFirst;        // +070
		KLinkedListNode *m_threadLocalPageLast;         // +074
		u32 m_unknown078;                               // +078
		s32 m_idealProcessor;                           // +07C
		u32 m_unknown080;                               // +080
		void *m_resourceLimits;                         // +084
		u32 m_unknown088;                               // +088
		u32 m_threadCount;                              // +08C
		u8 m_svcAccessControl[0x80 / 8];                // +090
		u32 m_interruptFlags[0x80 / 32];                // +0A0
		u32 m_kernelFlags;                              // +0B0
		u16 m_handleTableSize;                          // +0B4
		u16 m_kernelReleaseVersion;                     // +0B6
		KCodeSet *m_codeSet;                            // +0B8
		u32 m_processID;                                // +0BC
		u32 m_unknown0C0;                               // +0C0
		u32 m_unknown0C4;                               // +0C4
		KThread *m_mainThread;                          // +0C8
		//...more...
	};
	static_assert(offsetof(KProcess_8_0_0_New, m_svcAccessControl) == 0x090,
		"KProcess_8_0_0_New isn't the expected layout.");

	//------------------------------------------------------------------------------------------------
	// Done using illegal offsetof
	#pragma GCC diagnostic pop
}