From 476c31e973f20c2a745346adc3a506b0b3748430 Mon Sep 17 00:00:00 2001 From: Eileen Yoon Date: Tue, 23 Jan 2024 21:44:48 +0900 Subject: [PATCH] afk.rbep: Bootstrap ringbuf block size at runtime Make the ringbuffer class robust to various block sizes to generalize to both DCP and AOP. The first three blocks of the ringbuffer is reserved for exchanging size, rptr, wptr: ``` bufsize unk 00000000 00007e80 00070006 00000000 00000000 00000000 00000000 00000000 00000000 00000020 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000040 * rptr 00000080 00000600 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000a0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000c0 * wptr 00000100 00000680 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000120 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000140 * ``` Each block is spread out by some block_size multiple of 0x40 (step). The 0th block holds the size of the ringbuffer contents, the 1st block holds the rptr, and the 2nd block holds the wptr. The actual contents of the ringbuffer starts after the first three blocks, which will be collectively called the "header". However, this block_size isn't constant. DCP seems to consistently use 0x40, but AOP can use both 0x40/0x80. Since we're not given the block_size, so wemust bootstrap it. Recall we are given the total size of the rinbuffer in the mailbox message. Since we're always given the size of the ringbuffer `bufsize` at offset +block_size * 0 (or simply 0), and we can find the header size by subtracting `bufsize` from the total size. Since we also know that the header is always 3 blocks wide, we can divide the header size by 3 to obtain the block_size. Signed-off-by: Eileen Yoon --- proxyclient/m1n1/fw/afk/rbep.py | 64 +++++++++++++++++++++++++-------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/proxyclient/m1n1/fw/afk/rbep.py b/proxyclient/m1n1/fw/afk/rbep.py index 23654383..28d79848 100644 --- a/proxyclient/m1n1/fw/afk/rbep.py +++ b/proxyclient/m1n1/fw/afk/rbep.py @@ -54,15 +54,45 @@ class AFKEP_Shutdown_Ack(AFKEPMessage): class AFKError(Exception): pass +""" +The first three blocks of the ringbuffer is reserved for exchanging size, +rptr, wptr: + + bufsize unk +00000000 00007e80 00070006 00000000 00000000 00000000 00000000 00000000 00000000 +00000020 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +00000040 * rptr +00000080 00000600 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +000000a0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +000000c0 * wptr +00000100 00000680 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +00000120 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +00000140 * + +Note how each block is spread out by some block_size multiple of 0x40 +(step). Here, the block_size is 0x80. The 0th block holds the bufsize, +the 1st block holds the rptr, and the 2nd block holds the wptr. The +actual contents of the ringbuffer starts after the first three blocks, +which will be called the "header". Since we're *always* given the total +block size at offset +0x0 or +block_size*0, we can calculate the block +size by dividing by 3. +""" + class AFKRingBuf(Reloadable): BLOCK_SIZE = 0x40 + BLOCK_COUNT = 3 def __init__(self, ep, base, size): self.ep = ep self.base = base bs, unk = struct.unpack(" (self.bufsize - self.rptr): - hdr = self.read_buf(3 * self.BLOCK_SIZE, 16) + hdr = self.read_buf(base, 16) self.rptr = 16 magic, size = struct.unpack("<4sI", hdr[:8]) assert magic in [b"IOP ", b"AOP "] - payload = self.read_buf(3 * self.BLOCK_SIZE + self.rptr, size) - self.rptr = (align_up(self.rptr + size, self.BLOCK_SIZE)) % self.bufsize + payload = self.read_buf(base + self.rptr, size) + self.rptr = (align_up(self.rptr + size, self.stride)) % self.bufsize self.update_rptr(self.rptr) yield hdr[8:] + payload self.wptr = self.get_wptr() @@ -108,6 +143,7 @@ class AFKRingBuf(Reloadable): self.update_rptr(self.rptr) def write(self, data): + base = self.stride * 3 # after header (size, rptr, wptr) hdr2, data = data[:8], data[8:] self.rptr = self.get_rptr() @@ -115,19 +151,19 @@ class AFKRingBuf(Reloadable): raise AFKError("Ring buffer is full") hdr = struct.pack("<4sI", b"IOP ", len(data)) + hdr2 - self.write_buf(3 * self.BLOCK_SIZE + self.wptr, hdr) + self.write_buf(base + self.wptr, hdr) if len(data) > (self.bufsize - self.wptr - 16): if self.rptr < 0x10: raise AFKError("Ring buffer is full") - self.write_buf(3 * self.BLOCK_SIZE, hdr) + self.write_buf(base, hdr) self.wptr = 0 if self.wptr < self.rptr and self.wptr + 0x10 + len(data) >= self.rptr: raise AFKError("Ring buffer is full") - self.write_buf(3 * self.BLOCK_SIZE + self.wptr + 0x10, data) - self.wptr = align_up(self.wptr + 0x10 + len(data), self.BLOCK_SIZE) % self.bufsize + self.write_buf(base + self.wptr + 0x10, data) + self.wptr = align_up(self.wptr + 0x10 + len(data), self.stride) % self.bufsize self.update_wptr(self.wptr) return self.wptr