fxdoc/asm/fx@3.10/%003.txt

190 lines
6.5 KiB
Plaintext

Syscall %003 from Graph 35+E II OS 3.10
Disassembly objective:
Understand how TLB misses are handled to hopefully find a stable way of
calling the OS to manage the TLB from gint.
Conclusions:
* %003 answers the TLB miss by reading page values from an array in RAM. This
array is likely populated from filesystem when the add-in is loaded. %003
only answers TLB misses from ROM, which supports the idea that RAM pages
remain mapped all the time.
* %016 is the System ERROR popup; I haven't disassembled it yet, but I found
the "System ERROR!!" string in it so no doubt is possible.
* The subroutine at <80011238> loads to TLB a value of PTEH with ASID=0, so
ASID is probably staying at 0 all the time.
Discovered RAM memory:
0x8800c944: u32[] ADDIN_PAGE_TABLE
Page table for the add-in. Each entry is a pointer to ROM or P2 ROM.
-> Entries with NULL are considered invalid.
-> Other values are masked & 0x1fffffff and put to PTEL; clearly, these are
the matching physical addresses.
0x8800d144: u32 NEXT_TLB_EVICTION
Number of the next TLB entry to be evicted on a TLB miss. This varies
between 0 and 53 only, making sure that entries 54..63 remain in the TLB at
all times. According to experience, this covers RAM mappings and the 4k
page mapping NULL to ROM.
<%003 vbr_tlb_exception>
@PTEH @TEA Address that generated the TLB miss
Also takes some input from the stack, 54 bytes deep into the caller's frame
(likely saved registers from calling process) in case of error.
Stack> || r14 pr (likely caller's SPC:u32) (phys_addr:u32) (108)
(PTEH & 0xfffff000 = VPN; on error, TEA)
# Fill up the stack; r6=00300000
800113ce: 2fe6 mov.l r14, @-r15
800113d0: 4f22 sts.l pr, @-r15
800113d2: 7ff0 add #-16, r15
800113d4: eeff mov #-1, r14
800113d6: e1f0 mov #-16, r1
800113d8: 4e18 shll8 r14
800113da: e630 mov #48, r6
800113dc: 4e28 shll16 r14
800113de: 4118 shll8 r1
800113e0: 62e2 mov.l @r14, r2
800113e2: 4628 shll16 r6
800113e4: 2219 and r1, r2
800113e6: 2f22 mov.l r2, @r15
#---
# TLB miss resolution
#---
# If PTEH.VPN < 00300000, fail resolution
800113e8: 61f2 mov.l @r15, r1
800113ea: 3162 cmp/hs r6, r1
800113ec: 8b13 bf <80011416>
# r0 = (VPN - 00300000) >> 12 = VPN's page number in add-in ROM
800113ee: e16c mov #108, r1
800113f0: 1f11 mov.l r1, @(4,r15)
800113f2: 60f2 mov.l @r15, r0
800113f4: e2f4 mov #-12, r2
800113f6: d53a mov.l 0x8800c944, r5
800113f8: 3068 sub r6, r0
800113fa: 402d shld r2, r0
# phys_addr = ADDIN_PAGE_TABLE[r0] & 0x1fffffff; if NULL, fail resolution
800113fc: 4008 shll2 r0
800113fe: 065e mov.l @(r0,r5), r6
80011400: 2668 tst r6, r6
80011402: 8908 bt <80011416>
80011404: d237 mov.l 0x1fffffff, r2
80011406: 2629 and r2, r6
80011408: 1f62 mov.l r6, @(8,r15)
# <80011238>(VPN, phys_addr, 108)
8001140a: 56f1 mov.l @(4,r15), r6
8001140c: 64f2 mov.l @r15, r4
8001140e: bf13 bsr <80011238>
80011410: 55f2 mov.l @(8,r15), r5
80011412: a002 bra <8001141a>
80011414: 0009 nop
# If resolution fails, set VPN=NULL
80011416: e100 mov #0, r1
80011418: 2f12 mov.l r1, @r15
#---
# When resolution fails (if VPN is now NULL)
#---
# r0 = GetStackPtr() + 68 = 54 bytes under this function's frame; likely the
# value of SPC stored by the interrupt handler.
8001141a: 61f2 mov.l @r15, r1
8001141c: 2118 tst r1, r1
8001141e: 8b0b bf <80011438>
80011420: d731 mov.l %3fe GetStackPtr, r7
80011422: 54e3 mov.l @(12,r14), r4
80011424: 470b jsr @r7
80011426: 2f42 mov.l r4, @r15
80011428: 7044 add #68, r0
8001142a: 1f03 mov.l r0, @(12,r15)
8001142c: 51f3 mov.l @(12,r15), r1
8001142e: 6612 mov.l @r1, r6
80011430: 1f63 mov.l r6, @(12,r15)
# System_ERROR_popup(TEA, <stack value from above>, <again>)
80011432: 64f2 mov.l @r15, r4
80011434: beb2 bsr %016 System_ERROR_popup
80011436: 55f3 mov.l @(12,r15), r5
#---
# Epilogue
#---
80011438: 7f10 add #16, r15
8001143a: 4f26 lds.l @r15+, pr
8001143c: 000b rts
8001143e: 6ef6 mov.l @r15+, r14
#---
<80011238>
@r4 VPN to be updated
@r5 Corresponding physical address
@r6 Low bits of PTEL (=108 when called from %003)
Stack> || r15 (r6) (r5) (r4)
# r14 = ff000000 (MMU register base)
# r3 = a0000000 (random address for cache invalidation)
# MMUCR = (MMUCR & ffff03ff) | (NEXT_TLB_EVICTION << 8); this replace URC with
# the chosen NEXT_TLB_EVICTION entry to control eviction.
80011238: 2fe6 mov.l r14, @-r15
8001123a: 7ff4 add #-12, r15
8001123c: d7a1 mov.l 0x8800d144, r7
8001123e: eeff mov #-1, r14
80011240: 4e18 shll8 r14
80011242: d3a1 mov.l 0xffff03ff, r3
80011244: 4e28 shll16 r14
80011246: 1f62 mov.l r6, @(8,r15)
80011248: 2f42 mov.l r4, @r15
8001124a: 52e4 mov.l @(16,r14), r2
8001124c: 6172 mov.l @r7, r1
8001124e: 2239 and r3, r2
80011250: e3a0 mov #-96, r3
80011252: 4118 shll8 r1
80011254: 1f51 mov.l r5, @(4,r15)
80011256: 4108 shll2 r1
80011258: 4318 shll8 r3
8001125a: 221b or r1, r2
8001125c: 1e24 mov.l r2, @(16,r14)
8001125e: 4328 shll16 r3
# Invalidate instruction cache; load to TLB with
# -> PTEH=r4 (ASID implicitly 0)
# -> PTEL=r5|r6|0x110; when r6=108, this gives r5|0x17c:
# WT=0: Copy-back mode
# SH=0: Not shared (we're single process anyway)
# C=D=V=1: Cacheable, Dirty, Valid
# PR=3: All rings can read and write
# SZ=1: Page is 4k
80011260: 03e3 icbi @r3
80011262: 2e42 mov.l r4, @r14
80011264: e744 mov #68, r7
80011266: 4708 shll2 r7
80011268: 256b or r6, r5
8001126a: 257b or r7, r5
8001126c: 1e51 mov.l r5, @(4,r14)
8001126e: 0038 ldtlb
80011270: 0009 nop
80011272: 0009 nop
80011274: 0009 nop
# Invalidate instruction cache again; increment NEXT_TLB_EVICTION modulo 54
# and leave.
80011276: d193 mov.l 0x8800d144, r1
80011278: 03e3 icbi @r3
8001127a: ee36 mov #54, r14
8001127c: 6212 mov.l @r1, r2
8001127e: 32e3 cmp/ge r14, r2
80011280: 8901 bt <80011286>
80011282: a001 bra <80011288>
80011284: 7201 add #1, r2
80011286: e200 mov #0, r2
80011288: 2122 mov.l r2, @r1
8001128a: 7f0c add #12, r15
8001128c: 000b rts
8001128e: 6ef6 mov.l @r15+, r14