Talk:Undocumented SPU Channels

From PS3 Developer wiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Channel 67

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

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

  • 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)

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

  • 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

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