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
}
|