mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-22 06:33:03 +00:00
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 <eyn@gmx.com>
This commit is contained in:
parent
e76fc526e9
commit
476c31e973
1 changed files with 50 additions and 14 deletions
|
@ -54,15 +54,45 @@ class AFKEP_Shutdown_Ack(AFKEPMessage):
|
||||||
class AFKError(Exception):
|
class AFKError(Exception):
|
||||||
pass
|
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):
|
class AFKRingBuf(Reloadable):
|
||||||
BLOCK_SIZE = 0x40
|
BLOCK_SIZE = 0x40
|
||||||
|
BLOCK_COUNT = 3
|
||||||
|
|
||||||
def __init__(self, ep, base, size):
|
def __init__(self, ep, base, size):
|
||||||
self.ep = ep
|
self.ep = ep
|
||||||
self.base = base
|
self.base = base
|
||||||
|
|
||||||
bs, unk = struct.unpack("<II", self.read_buf(0, 8))
|
bs, unk = struct.unpack("<II", self.read_buf(0, 8))
|
||||||
assert (bs + 3 * self.BLOCK_SIZE) == size
|
# calculate stride
|
||||||
|
# bs + self.BLOCK_COUNT * stride) == size
|
||||||
|
assert((size - bs) % self.BLOCK_COUNT == 0)
|
||||||
|
stride = (size - bs) // self.BLOCK_COUNT
|
||||||
|
assert(stride % self.BLOCK_SIZE == 0)
|
||||||
|
self.stride = stride
|
||||||
self.bufsize = bs
|
self.bufsize = bs
|
||||||
self.rptr = 0
|
self.rptr = 0
|
||||||
self.wptr = 0
|
self.wptr = 0
|
||||||
|
@ -74,33 +104,38 @@ class AFKRingBuf(Reloadable):
|
||||||
return self.ep.iface.writemem(self.base + off, data)
|
return self.ep.iface.writemem(self.base + off, data)
|
||||||
|
|
||||||
def get_rptr(self):
|
def get_rptr(self):
|
||||||
return self.ep.asc.p.read32(self.base + self.BLOCK_SIZE)
|
return struct.unpack("<I", self.read_buf(self.stride * 1, 4))[0]
|
||||||
|
#return self.ep.asc.p.read32(self.base + self.BLOCK_SIZE)
|
||||||
|
|
||||||
def get_wptr(self):
|
def get_wptr(self):
|
||||||
return self.ep.asc.p.read32(self.base + 2 * self.BLOCK_SIZE)
|
return struct.unpack("<I", self.read_buf(self.stride * 2, 4))[0]
|
||||||
|
#return self.ep.asc.p.read32(self.base + 2 * self.BLOCK_SIZE)
|
||||||
|
|
||||||
def update_rptr(self, rptr):
|
def update_rptr(self, rptr):
|
||||||
self.ep.asc.p.write32(self.base + self.BLOCK_SIZE, self.rptr)
|
self.write_buf(self.stride * 1, struct.pack("<I", rptr))
|
||||||
|
self.ep.asc.p.write32(self.base + self.BLOCK_SIZE, rptr)
|
||||||
|
|
||||||
def update_wptr(self, rptr):
|
def update_wptr(self, wptr):
|
||||||
self.ep.asc.p.write32(self.base + 2 * self.BLOCK_SIZE, self.wptr)
|
self.write_buf(self.stride * 2, struct.pack("<I", wptr))
|
||||||
|
self.ep.asc.p.write32(self.base + 2 * self.BLOCK_SIZE, wptr)
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
self.wptr = self.get_wptr()
|
self.wptr = self.get_wptr()
|
||||||
|
|
||||||
|
base = self.stride * 3 # after header (size, rptr, wptr)
|
||||||
while self.wptr != self.rptr:
|
while self.wptr != self.rptr:
|
||||||
hdr = self.read_buf(3 * self.BLOCK_SIZE + self.rptr, 16)
|
hdr = self.read_buf(base + self.rptr, 16)
|
||||||
self.rptr += 16
|
self.rptr += 16
|
||||||
magic, size = struct.unpack("<4sI", hdr[:8])
|
magic, size = struct.unpack("<4sI", hdr[:8])
|
||||||
assert magic in [b"IOP ", b"AOP "]
|
assert magic in [b"IOP ", b"AOP "]
|
||||||
if size > (self.bufsize - self.rptr):
|
if size > (self.bufsize - self.rptr):
|
||||||
hdr = self.read_buf(3 * self.BLOCK_SIZE, 16)
|
hdr = self.read_buf(base, 16)
|
||||||
self.rptr = 16
|
self.rptr = 16
|
||||||
magic, size = struct.unpack("<4sI", hdr[:8])
|
magic, size = struct.unpack("<4sI", hdr[:8])
|
||||||
assert magic in [b"IOP ", b"AOP "]
|
assert magic in [b"IOP ", b"AOP "]
|
||||||
|
|
||||||
payload = self.read_buf(3 * self.BLOCK_SIZE + self.rptr, size)
|
payload = self.read_buf(base + self.rptr, size)
|
||||||
self.rptr = (align_up(self.rptr + size, self.BLOCK_SIZE)) % self.bufsize
|
self.rptr = (align_up(self.rptr + size, self.stride)) % self.bufsize
|
||||||
self.update_rptr(self.rptr)
|
self.update_rptr(self.rptr)
|
||||||
yield hdr[8:] + payload
|
yield hdr[8:] + payload
|
||||||
self.wptr = self.get_wptr()
|
self.wptr = self.get_wptr()
|
||||||
|
@ -108,6 +143,7 @@ class AFKRingBuf(Reloadable):
|
||||||
self.update_rptr(self.rptr)
|
self.update_rptr(self.rptr)
|
||||||
|
|
||||||
def write(self, data):
|
def write(self, data):
|
||||||
|
base = self.stride * 3 # after header (size, rptr, wptr)
|
||||||
hdr2, data = data[:8], data[8:]
|
hdr2, data = data[:8], data[8:]
|
||||||
self.rptr = self.get_rptr()
|
self.rptr = self.get_rptr()
|
||||||
|
|
||||||
|
@ -115,19 +151,19 @@ class AFKRingBuf(Reloadable):
|
||||||
raise AFKError("Ring buffer is full")
|
raise AFKError("Ring buffer is full")
|
||||||
|
|
||||||
hdr = struct.pack("<4sI", b"IOP ", len(data)) + hdr2
|
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 len(data) > (self.bufsize - self.wptr - 16):
|
||||||
if self.rptr < 0x10:
|
if self.rptr < 0x10:
|
||||||
raise AFKError("Ring buffer is full")
|
raise AFKError("Ring buffer is full")
|
||||||
self.write_buf(3 * self.BLOCK_SIZE, hdr)
|
self.write_buf(base, hdr)
|
||||||
self.wptr = 0
|
self.wptr = 0
|
||||||
|
|
||||||
if self.wptr < self.rptr and self.wptr + 0x10 + len(data) >= self.rptr:
|
if self.wptr < self.rptr and self.wptr + 0x10 + len(data) >= self.rptr:
|
||||||
raise AFKError("Ring buffer is full")
|
raise AFKError("Ring buffer is full")
|
||||||
|
|
||||||
self.write_buf(3 * self.BLOCK_SIZE + self.wptr + 0x10, data)
|
self.write_buf(base + self.wptr + 0x10, data)
|
||||||
self.wptr = align_up(self.wptr + 0x10 + len(data), self.BLOCK_SIZE) % self.bufsize
|
self.wptr = align_up(self.wptr + 0x10 + len(data), self.stride) % self.bufsize
|
||||||
|
|
||||||
self.update_wptr(self.wptr)
|
self.update_wptr(self.wptr)
|
||||||
return self.wptr
|
return self.wptr
|
||||||
|
|
Loading…
Reference in a new issue