DF-5767 / itd_offset_sim.py
# Faithful simulation of ohci_device_isoc_enter ITD-fill (ohci.c:1900-1965) # + QEMU hcd-ohci.c address computation, to find OOB DMA. PAGE=0x1000 def mk_offs(v): return 0xe000 | (v & 0x1fff) # OHCI_ITD_MK_OFFS def qemu_start(psw, bp0, be): if (psw & 0x1000)==0: return (bp0 & ~0xfff) | (psw & 0xfff) return (be & ~0xfff) | (psw & 0xfff) def build(frlens, buf_page_off, phys_base): """returns list of (frame_idx, intended_addr, qemu_addr, be, bp0) per ITD""" out=[]; buf_off=0; length=0; ncur=0; itd=[] plen=frlens[:] starts=[0] for i,x in enumerate(plen[1:],1): starts.append(starts[-1]+plen[i-1]) n=len(plen); i=0 while i < n: itd.append((i, length)) # frame i starts at cumulative 'length' buf_off += plen[i]; length += plen[i]; ncur += 1; i+=1 if ncur==8 or (length & 0xf000) or i==n: # fill ITD: bp0 = page of first byte first = buf_off - length bp0_abs = phys_base + buf_page_off + first be_abs = phys_base + buf_page_off + buf_off - 1 bp0 = bp0_abs & ~0xfff po = (phys_base + buf_page_off + first) & 0xfff for (fi, cum) in itd: psw = mk_offs(po + cum) intended = bp0_abs + cum qa = qemu_start(psw, bp0, be_abs) out.append((fi, plen[fi], intended, qa, be_abs, bp0_abs)) length=0; ncur=0; itd=[] return out # 15 frames x 1023 bytes = 15345 bytes, buffer starts page-aligned (phys 0x100000) fr=[1023]*30 res=build(fr, 0, 0x100000) end_of_buffer = 0x100000 + sum(fr) - 1 print("buffer: [0x%x .. 0x%x]" % (0x100000, end_of_buffer)) prev_be=None for fi,ln,intended,qa,be,bp0 in res: tag="" if qa != intended: tag += " MISMAP" # write range for IN frame: [qa, qa+ln-1] clamped by QEMU to page(qa) last = min(qa+ln-1, (qa & ~0xfff)+0xfff) if last > end_of_buffer: tag += " *** OOB-WRITE past buffer end by 0x%x" % (last-end_of_buffer) if fi==0 or tag: print("f%-2d len=%4d intended=0x%06x qemu=0x%06x be=0x%06x%s" % (fi,ln,intended,qa,be,tag)) |