[OpenBIOS] Running client with MMU off

BALATON Zoltan balaton at eik.bme.hu
Mon Jun 9 22:08:36 CEST 2014

On Mon, 9 Jun 2014, Mark Cave-Ayland wrote:
> A quick look around shows that you probably want to look at 
> DEBUG_MMU/DEBUG_BAT in target-ppc/mmu_has32.c. And I'm not even a PPC guy :)

Me neither... These give some more debug output but they are only useful 
for debugging BATs not debugging translation via the TLB as it only prints 
TLB address and hashes so I can only see if the TLB was consulted but not 
the address that was looked up.

> Therefore for a load/store not to fault on real hardware then that means the 
> entry is already in the TLB, i.e. it must have already been accessed AND also 
> not been previously evicted by hash collision (see hash_page32).

Unfortunately PPC has many other ways to translate an address not only via 
the TLB so this is not that simple. I suspect the TLB is not used on Macs 
during boot but BAT translation is because MorphOS only disables the MMU 
during replacing the BAT registers.

> Hence you need to trace through previous accesses to the addresses that fault 
> and determine why the entry is no longer in the TLB in QEMU/OpenBIOS when it 
> should be there on real hardware.

The vectors are only accessed by OpenBIOS during the inital copying of the 
vectors before setting up the MMU then by MorphOS when copying it's 
vectors that cause the exception which crashes. No other access inbetween 
so it's not evicted from TLB as it never gets into it.

>> Actually after writing the sr0-sr15 and sdr1 registers it clears the MMU
>> bits and then writes to the ibat and dbat registers and seems to set up
>> the TLB and then enable the bits in the MSR. So maybe Apple relies on
>> translations in these registers and that's why it works there.
> Not that I have the definitive answer, but I can't see why on earth Apple 
> would map the trap table with an IBAT/DBAT. My understanding is that these 
> are designed for optimally mapping large blocks of memory, e.g. kernels, so 
> why would you implement a second form of translation in a BIOS environment 
> when you already have limited resources? It just doesn't make any sense. Plus 
> you still get a fault once you effectively "preload" the trap table into the 
> TLB with your fake access above, so something else is still missing from the 
> picture.

After more experiments I think I got a bit closer to the solution. The 
other exeption I got with my last patch while setting the sr0 register was 
because the value was read from a local variable on the stack which 
generated the exception. With this patch:

--- a/openbios-devel/arch/ppc/qemu/ofmem.c
+++ b/openbios-devel/arch/ppc/qemu/ofmem.c
@@ -531,6 +531,32 @@ setup_mmu(unsigned long ramsize)
          asm volatile("mtsrin %0,%1" :: "r" (sr_base + i), "r" (j));

+    /* Add permanent translations for the first 128MB and the client 
stack area
+     * via BAT registers on 32bit CPUs where this is supported */
+    if (!is_ppc64()) {
+        unsigned long stack_addr;
+        mBAT bat;
+        memset(&bat, 0, sizeof(bat));
+        bat.batu.bl = 0x3ff; /* 128 MB */
+        bat.batu.vs = 1; /* supervisor access */
+        bat.batl.pp = 2; /* read/write */
+        mtspr(S_DBAT0L, bat.batl);
+        mtspr(S_IBAT0L, bat.batl);
+        mtspr(S_DBAT0U, bat.batu);
+        mtspr(S_IBAT0U, bat.batu);
+        stack_addr = get_heap_top();
+        /* only add if not overlapping the previous one */
+        if (stack_addr > 0x8000000) {
+            bat.batu.bepi = stack_addr >> 17;
+            bat.batu.bl = 1; /* 256 kB */
+            bat.batl.brpn = stack_addr >> 17;
+            mtspr(S_DBAT1L, bat.batl);
+            mtspr(S_DBAT1U, bat.batu);
+        }
+        asm volatile("isync");
+    }

      ofmem = ofmem_arch_get_private();

it boots but only with 256MB of memory.

With 128MB it will overwrite the stack as I've found earlier here:

With 512MB it will freeze after clearing the TLB and replacing BAT 
registers with it's own values like this:

Set IBAT0l to 00000000 (0041ce54)
Set IBAT0u to 00000000 (0041ce54)
Flush BAT from 00000000 to 00020000 (00000000)
Flush done
Flush BAT from 00000000 to 00020000 (00000000)
Flush done
Set IBAT1l to f0000012 (0041ce54)
Set IBAT1u to f0001ffe (0041ce54)
Flush BAT from 00000000 to 10000000 (0ffe0000)
Flush done
Flush BAT from f0000000 to 00000000 (0ffe0000)
Flush done
Set IBAT2l to 00000000 (0041ce54)
Set IBAT2u to 00000000 (0041ce54)
Set IBAT3l to 00000012 (0041ce54)
Set IBAT3u to 00000ffe (0041ce54)
Flush BAT from 00000000 to 08000000 (07fe0000)
Flush done
Flush BAT from 00000000 to 08000000 (07fe0000)
Flush done
Set DBAT0l to f000002a (0041ce54)
Set DBAT0u to f0001ffe (0041ce54)
Flush BAT from 00000000 to 10000000 (0ffe0000)
Flush done
Flush BAT from f0000000 to 00000000 (0ffe0000)
Flush done
Set DBAT1l to 00000012 (0041ce54)
Set DBAT1u to 00001ffe (0041ce54)
Flush BAT from 1fdc0000 to 2fdc0000 (0ffe0000)
Flush done
Flush BAT from 00000000 to 10000000 (0ffe0000)
Flush done
Set DBAT2l to 00000000 (0041ce54)
Set DBAT2u to 00000000 (0041ce54)
Set DBAT3l to 8000002a (0041ce54)
Set DBAT3u to 80001ffe (0041ce54)

and then trying to access a variable on the stack:

0x0041cf40:  lmw     r13,20(r1)
0x0041cf44:  addi    r1,r1,96
0x0041cf48:  blr

htab_base 0000000000000000 htab_mask 000000000000ffff hash 000000000000fde7
0 htab=0000000000000000/000000000000ffff vsid=0 ptem=3f hash=000000000000fde7
1 htab=0000000000000000/000000000000ffff vsid=0 api=3f hash=ffffffffffff0218
Raise exception at 0041cf40 => 00000002 (00)

r0             0x3030   12336
r1             0x1fde7e70       534675056

which is not covered by any translation now. So I think the stack must be 
in the first 256MB to which a translation is added to the BAT and this is 
why it works with 256MB of memory. Thus to be complete the stack should be 
moved from the end of the memory where it is now (described in a comment 
in arch/ppc/qemu/start.S) to somwhere else. But where? There's another 
comment in arch/ppc/qemu/ofmem.c that seems to originate from here:


but seems it has changed at the origin since it was copied. Does anyone 
know a good location that is left free by the boot loaders we care about 
where the stack could be placed within the first 256MB? MoprhOS seems to 
start using memory from the end so maybe the stack should not be there.
Any more ideas?


More information about the OpenBIOS mailing list