Talk:Undocumented SPU Channels: Difference between revisions
Jump to navigation
Jump to search
m (→Channel 67) |
|||
(11 intermediate revisions by 6 users not shown) | |||
Line 1: | Line 1: | ||
== Channel 67 == | == Channel 67 == | ||
Line 47: | Line 45: | ||
== Channel 64 == | == Channel 64 == | ||
Used to control isolation-mode persistent storage (w:ch72/r:ch73) and probably config ring storage (r:ch67). | |||
Other values written to channel 64 (on bootldr): 0x00, 0x02, 0x20000 | Other values written to channel 64 (on bootldr): 0x00, 0x02, 0x20000 | ||
=== Isolation-mode control flags === | |||
* 0x0 : clear config ring storage? | |||
* 0x2 : call hardware isolation exit function | |||
* (0x1 | 0x2) = 0x3 : call hardware isolation load function, it will wait for isolated binary address through SPU_RdSigNotify1 & SPU_RdSigNotify2 | |||
* 0x10000 : reset persistent storage r/w index (writes to ch72 and reads from ch73 will start at index zero) | |||
* 0x20000 : lock persistent storage write | |||
* 0x40000 : lock persistent storage read | |||
* (0x20000 | 0x40000) = 0x60000 : lock persistent storage r/w (reading from ch73 will return zero as long as the current isolated session lasts) | |||
== Channel 13 (SPU_RdMachStat) == | |||
This channel used for some check before to write 0x60000 to ch64 (appldr, lv1ldr, lv2ldr, isoldr) | |||
<pre>uint32_t spu_machine_status = spu_rdch(13); | |||
if ((spu_machine_status & 0x40000) != 0) | |||
{ | |||
return -1; | |||
} | |||
else | |||
{ | |||
spu_wrch(64, 0x60000); | |||
return 0; | |||
} | |||
</pre> | |||
== Some observations and questions == | |||
* spu_rdchcnt() returns 1 on the following channels: 64, 69, 70, 71, 74, but 0 on 73, why? | |||
* It seems that LS isn't erased when calling the isolation load function from ch64, could we take some advantage from that? | |||
* How many other undocumented channels exists? Is there any possibility to determine if specific channel exists? | |||
* What is the purpose of other undocumented channels? H/W decryption facility? Validation? Something else? | |||
* Is it possible to refill config ring storage? | |||
* http://paste.ubuntu.com/23453452/ | |||
== Utility functions for channel fuzzing == | |||
<syntaxhighlight lang="c"> | |||
uint32_t get_channel_count(uint32_t n) { | |||
static uint32_t f[] __attribute__ ((aligned(16))) = { | |||
0x01E00003, // rchcnt $3, $ch(?) | |||
0x35000000, // bi $LR | |||
0x4020007F, // lnop | |||
}; | |||
f[0] &= ~(0x7F << 7); | |||
f[0] |= (n & 0x7F) << 7; | |||
uint32_t (* pf)(void) = (void*)&f; | |||
si_sync(); | |||
return pf(); | |||
} | |||
uint32_t read_channel(uint32_t n) { | |||
static uint32_t f[] __attribute__ ((aligned(16))) = { | |||
0x01A00003, // rdch $3, $ch(?) | |||
0x35000000, // bi $LR | |||
0x4020007F, // lnop | |||
}; | |||
f[0] &= ~(0x7F << 7); | |||
f[0] |= (n & 0x7F) << 7; | |||
uint32_t (* pf)(void) = (void*)&f; | |||
si_sync(); | |||
return pf(); | |||
} | |||
void write_channel(uint32_t n, uint32_t value) { | |||
static uint32_t f[] __attribute__ ((aligned(16))) = { | |||
0x21A00003, // wrch $ch(?), $3 | |||
0x35000000, // bi $LR | |||
0x4020007F, // lnop | |||
}; | |||
f[0] &= ~(0x7F << 7); | |||
f[0] |= (n & 0x7F) << 7; | |||
void (* pf)(uint32_t) = (void*)&f; | |||
si_sync(); | |||
pf(value); | |||
} | |||
</syntaxhighlight> |
Latest revision as of 14:38, 30 November 2021
Channel 67[edit source]
Used to get the config ring.
Use is similar to channel 73.
uint8_t expectedConfigRing65[]; uint8_t expectedConfigRing90[]; function _start+1340() { //extracted from bootloader on 0x1A datecode console uint64_t vr = getSPU_VR(); //First active SPE priv1 SPU_VR register uint32_t toIgnore; uint32_t toRead; uint8_t expectedConfigRing; uint8_t readedConfigRing[]; switch (vr) { case 0x201: case 0x202: //90nm console toIgnore = 0xA6; toRead = 0x156; expectedConfigRing = expectedConfigRing90; break; default: //65nm console toIgnore = 0xBB; toRead = 0x152; expectedConfigRing = expectedConfigRing90; } unsigned int index; for (index = 0; index < toIgnore>>3; index++) { rdch(67); } for (index = 0; index < toRead; index++) { readedConfigRing[index] = rdch(67) & 0xFF; } while (moreBitFieldsToCheck) { checkConfigRingField(expectedConfigRing, readedConfigRing, field, .....); } }
Channel 64[edit source]
Used to control isolation-mode persistent storage (w:ch72/r:ch73) and probably config ring storage (r:ch67).
Other values written to channel 64 (on bootldr): 0x00, 0x02, 0x20000
Isolation-mode control flags[edit source]
- 0x0 : clear config ring storage?
- 0x2 : call hardware isolation exit function
- (0x1 | 0x2) = 0x3 : call hardware isolation load function, it will wait for isolated binary address through SPU_RdSigNotify1 & SPU_RdSigNotify2
- 0x10000 : reset persistent storage r/w index (writes to ch72 and reads from ch73 will start at index zero)
- 0x20000 : lock persistent storage write
- 0x40000 : lock persistent storage read
- (0x20000 | 0x40000) = 0x60000 : lock persistent storage r/w (reading from ch73 will return zero as long as the current isolated session lasts)
Channel 13 (SPU_RdMachStat)[edit source]
This channel used for some check before to write 0x60000 to ch64 (appldr, lv1ldr, lv2ldr, isoldr)
uint32_t spu_machine_status = spu_rdch(13); if ((spu_machine_status & 0x40000) != 0) { return -1; } else { spu_wrch(64, 0x60000); return 0; }
Some observations and questions[edit source]
- spu_rdchcnt() returns 1 on the following channels: 64, 69, 70, 71, 74, but 0 on 73, why?
- It seems that LS isn't erased when calling the isolation load function from ch64, could we take some advantage from that?
- How many other undocumented channels exists? Is there any possibility to determine if specific channel exists?
- What is the purpose of other undocumented channels? H/W decryption facility? Validation? Something else?
- Is it possible to refill config ring storage?
- http://paste.ubuntu.com/23453452/
Utility functions for channel fuzzing[edit source]
uint32_t get_channel_count(uint32_t n) {
static uint32_t f[] __attribute__ ((aligned(16))) = {
0x01E00003, // rchcnt $3, $ch(?)
0x35000000, // bi $LR
0x4020007F, // lnop
};
f[0] &= ~(0x7F << 7);
f[0] |= (n & 0x7F) << 7;
uint32_t (* pf)(void) = (void*)&f;
si_sync();
return pf();
}
uint32_t read_channel(uint32_t n) {
static uint32_t f[] __attribute__ ((aligned(16))) = {
0x01A00003, // rdch $3, $ch(?)
0x35000000, // bi $LR
0x4020007F, // lnop
};
f[0] &= ~(0x7F << 7);
f[0] |= (n & 0x7F) << 7;
uint32_t (* pf)(void) = (void*)&f;
si_sync();
return pf();
}
void write_channel(uint32_t n, uint32_t value) {
static uint32_t f[] __attribute__ ((aligned(16))) = {
0x21A00003, // wrch $ch(?), $3
0x35000000, // bi $LR
0x4020007F, // lnop
};
f[0] &= ~(0x7F << 7);
f[0] |= (n & 0x7F) << 7;
void (* pf)(uint32_t) = (void*)&f;
si_sync();
pf(value);
}