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
|
/* dtm reference (dtm2) -- named functions
* generated by fw/ta_re.py -- do not edit
* reference: dtm2.elf
* functions: 14 total in build, 14 named, 0 anonymous
* porting tiers: {"DISPATCH": 0, "EXACT": 9, "FUZZY": 0, "MNEM": 0, "ambiguous": 4, "cmd_protos": 0, "comments": 12, "dispatch_conflict": 0, "none": 1, "protos": 9, "relabelled": 0, "types": 1}
*
* Addresses are omitted and functions are ordered by NAME so that the same
* function lines up across versions. See the .index.json sidecar for
* name -> address.
*
* CAUTION on ported names: a name is only an identity claim at tier=EXACT.
* At tier=MNEM/FUZZY the bytes differ from the reference, so any ADDRESS or
* CONTENT HASH embedded in the name (e.g. *_4025F8, gcp_lib_<hash8>_*) still
* refers to the REFERENCE build and does not describe this one.
*/
/* ==== TA_InvokeCommandEntryPoint [tier=EXACT size=94] ==== */
// GP command 5 (dtm_entry_tbl[4]) - the host command surface.
// Requires (paramTypes & 0xF) == 7, params != 0 and params[0].size >= 0x50.
// buf = params[0].buffer; command id = *buf; handlers receive buf+16
// (the source is 'v5 + 4' with v5 typed int*, i.e. +16 bytes).
// cmd 2 -> dtm_cmd_topology_update
// cmd 3 -> dtm_cmd_set_flag
// cmd 4 -> dtm_cmd_topology_update_v2
// The handler result is written back to buf+8.
int __fastcall TA_InvokeCommandEntryPoint(int a1, int a2, char a3, int a4)
{
int result; // r0
struct dtm_req *v5; // r4
unsigned int cmd_id; // r0
int updated; // r0
unsigned int v8; // r1
result = dword_4010B8 + 6;
if ( (a3 & 0xF) == 7 && a4 != 0 )
{
if ( *(_DWORD *)(a4 + 4) < 0x50u )
return dword_4010B8 + 16;
v5 = *(struct dtm_req **)a4;
if ( *(_DWORD *)a4 == 0 )
return dword_4010B8;
cmd_id = v5->cmd_id;
if ( v5->cmd_id == 4 )
{
updated = dtm_cmd_topology_update_v2(a1: v5->args);
}
else if ( cmd_id == 3 )
{
updated = dtm_cmd_set_flag(a1: v5->args);
}
else
{
if ( cmd_id != 2 )
{
v8 = 1;
result = dword_4010B8;
goto LABEL_15;
}
updated = dtm_cmd_topology_update(a1: (int *)v5->args);
}
v8 = updated;
result = 0;
LABEL_15:
v5->unk08 = v8;
}
return result;
}
/* ==== asd_rpc_100_topology_update [tier=EXACT size=34] ==== */
// SVC 0xF2 -> ASD, opcode 0x100 (asd_topology_update).
// Frame {0x100, link_index, descriptor_ptr}; ASD bounds the index to 0x3F and
// region-validates the descriptor for 0x40 bytes.
int __fastcall asd_rpc_100_topology_update()
{
_DWORD v5[7]; // [sp+0h] [bp-1Ch] BYREF
bzero_core(result: v5, a2: 0x18u);
__asm { SVC 0xF2 }
return 2;
}
/* ==== asd_rpc_101_topology_remove [tier=EXACT size=32] ==== */
// SVC 0xF2 -> ASD, opcode 0x101 (asd_topology_remove). Frame {0x101, link_index}.
int __fastcall asd_rpc_101_topology_remove()
{
_DWORD v5[6]; // [sp+0h] [bp-18h] BYREF
bzero_core(result: v5, a2: 0x18u);
__asm { SVC 0xF2 }
return 2;
}
/* ==== asd_rpc_1C0 [tier=EXACT size=32] ==== */
// SVC 0xF2 -> ASD (target process 2), opcode 0x1C0. 0x18-byte frame {opcode, arg}.
int __fastcall asd_rpc_1C0()
{
_DWORD v5[6]; // [sp+0h] [bp-18h] BYREF
bzero_core(result: v5, a2: 0x18u);
__asm { SVC 0xF2 }
return 2;
}
/* ==== bzero_core [tier=EXACT size=78] ==== */
// Zero-fill helper (32-byte unrolled tail-handling). Same SDK routine as the
// identical function in HDCP, ASD and RAS.
_DWORD *__fastcall bzero_core(_DWORD *result, unsigned int a2)
{
bool v2; // cf
unsigned int v3; // r1
_DWORD *v4; // r0
int v5; // r1
int v6; // r1
v2 = a2 >= 0x20;
v3 = a2 - 32;
do
{
if ( !v2 )
break;
*result = 0;
result[1] = 0;
result[2] = 0;
result[3] = 0;
v4 = result + 4;
*v4 = 0;
v4[1] = 0;
v4[2] = 0;
v4[3] = 0;
result = v4 + 4;
v2 = v3 >= 0x20;
v3 -= 32;
}
while ( v2 );
v2 = __CFSHL__(v3, 28);
v5 = v3 << 28;
if ( v2 )
{
*result = 0;
result[1] = 0;
result[2] = 0;
result[3] = 0;
result += 4;
}
if ( v5 < 0 )
{
*result = 0;
result[1] = 0;
result += 2;
}
v2 = __CFSHL__(v5, 2);
v6 = 4 * v5;
if ( v2 )
*result++ = 0;
if ( v6 != 0 )
{
if ( v6 < 0 )
{
*(_WORD *)result = 0;
result = (_DWORD *)((char *)result + 2);
}
if ( (v6 & 0x40000000) != 0 )
{
*(_BYTE *)result = 0;
return (_DWORD *)((char *)result + 1);
}
}
return result;
}
/* ==== dtm_TA_CloseSessionEntryPoint [tier=ENTRY size=2] ==== */
void dtm_TA_CloseSessionEntryPoint()
{
;
}
/* ==== dtm_TA_CreateEntryPoint [tier=ENTRY size=4] ==== */
int dtm_TA_CreateEntryPoint()
{
return 0;
}
/* ==== dtm_TA_DestroyEntryPoint [tier=ENTRY size=2] ==== */
void dtm_TA_DestroyEntryPoint()
{
;
}
/* ==== dtm_TA_OpenSessionEntryPoint [tier=ENTRY size=4] ==== */
int dtm_TA_OpenSessionEntryPoint()
{
return 0;
}
/* ==== dtm_cmd_set_flag [tier=EXACT size=22] ==== */
// Host command 3. Null-checks the request then forwards *req to ASD opcode 0x1C0
// via asd_rpc_1C0. Returns 3 on a null request.
int __fastcall dtm_cmd_set_flag(_DWORD *a1)
{
if ( a1 != nullptr )
return asd_rpc_1C0() != 0;
else
return 3;
}
/* ==== dtm_cmd_topology_update [tier=EXACT size=94] ==== */
// Host command 2. If req[1] != 0: bounds req[9] <= 0x17, builds a 5-dword topology
// descriptor from req[2..6] plus the 64-bit pair at req[7..8], and issues ASD 0x100
// (asd_rpc_100_topology_update). If req[1] == 0 it instead issues ASD 0x101
// (asd_rpc_101_topology_remove) with *req. Deepest read req[9] -> buf+52.
int __fastcall dtm_cmd_topology_update(int *a1)
{
int v2; // r0
_DWORD v3[7]; // [sp+24h] [bp-1Ch] BYREF
if ( a1 == nullptr )
return 3;
if ( a1[1] != 0 )
{
if ( (unsigned int)a1[9] > 0x17 )
return 2;
bzero_core(result: v3, a2: 0x1Cu);
v2 = asd_rpc_100_topology_update();
}
else
{
v2 = asd_rpc_101_topology_remove();
}
return v2 != 0;
}
/* ==== dtm_cmd_topology_update_v2 [tier=EXACT size=120] ==== */
// Host command 4. Larger form of dtm_cmd_topology_update: bounds req[9] <= 0x17 and
// marshals req[2..14] into an 11-dword descriptor, normalising req[13] to 0/1/2.
// Deepest read req[14] -> buf+72, +4 = buf+76, against the buf size gate of 0x50 (80).
int __fastcall dtm_cmd_topology_update_v2(_DWORD *a1)
{
int v3; // r0
int v4; // r3
_DWORD v5[5]; // [sp+2Ch] [bp-14h] BYREF
if ( a1 == nullptr )
return 3;
if ( a1[1] != 0 )
{
if ( a1[9] > 0x17u )
return 2;
bzero_core(result: v5, a2: 0x14u);
v4 = a1[13];
v5[2] = a1[14];
if ( v4 != 1 )
v4 = 2 * (v4 == 2);
v5[1] = v4;
v3 = asd_rpc_100_topology_update();
}
else
{
v3 = asd_rpc_101_topology_remove();
}
return v3 != 0;
}
/* ==== dtm_ta_main_loop [tier=EXACT size=148] ==== */
// DTM TA entry (header +0x10). Waits on SVC 0xF0, reads the GP command from frame[0],
// vectors through dtm_entry_tbl (1..5), calls it, then replies with SVC 0xF1 and loops.
// An unknown command id spins forever in a tight self-loop.
void __fastcall __noreturn dtm_ta_main_loop(int *a1)
{
int v6; // r1
void (__cdecl *v7)(); // r12
while ( 1 )
{
__asm { SVC 0xF0 }
v6 = *a1;
if ( *a1 == 1 )
{
v7 = (void (__cdecl *)())dtm_TA_CreateEntryPoint;
}
else
{
switch ( v6 )
{
case 2:
v7 = (void (__cdecl *)())off_401250;
break;
case 3:
v7 = (void (__cdecl *)())off_401254;
break;
case 4:
v7 = (void (__cdecl *)())off_401258;
break;
case 5:
v7 = (void (__cdecl *)())off_40125C;
break;
default:
while ( 1 )
;
}
}
v7();
__asm { SVC 0xF1 }
}
}
/* ==== start [tier=IDA size=1832] ==== */
// DTM TA header. magic 0x4154 'TA' -> host-loadable via LOAD_TA/INVOKE_CMD.
// load_base 0x400000, data_base == image_end == 0x402000 (no .data/.bss),
// entry 0x4011AC, stack guard VA 0x401240.
void __fastcall __noreturn start(int a1, int a2, int a3)
{
int v3; // r5
int v4; // r6
char v5; // r7
int v6; // r4
v6 = a3 + (v3 >> 6);
while ( 1 )
{
v4 *= 16;
*(_BYTE *)(v6 + 1) = v5;
*(_DWORD *)(v4 + 20) = v6;
*(_DWORD *)(((__int16)v6 >> 15) + 0x10) = v4;
*(_BYTE *)(v4 + 1) = 0;
}
}
|