Re: L4Re: Boot module copying and the MIPS Creator CI20

Paul Boddie <[email protected]> Fri, 12 May 2023 01:23:14 +0200
Newsgroups gmane.comp.micro-kernel.l4.devel
Message-ID <20289312.FDuiAd3TX7@jason>
On Wednesday, 10 May 2023 12:35:10 CEST Paul Boddie wrote:
> On Wednesday, 10 May 2023 10:52:59 CEST Philipp Eppelt wrote:
> > 
> > I say that this bit should be cleared. The two 256MB regions also point
> > to the intention that Status.ERL is clear and thus there is no
> > unchached+unmapped useg.
> 
> I agree. I'll try and see if this can be done, but there did seem to be
> something preventing it when I tried before.

Well, I persisted here and found that trying to map 256MB pages will not work 
on the CI20, as the JZ4780 programming manual indeed suggests, but 16MB pages 
do work.

One particularly odd thing about the existing bootstrap code is that it tries 
to map a pair of 256MB pages at the base of physical memory (corresponding to 
the base of virtual memory) with the second one described by the EntryLo1 
register as follows:

li    $8, 0x0080001F     // odd page @256MB, cached, dirty, valid, global
mtc0  $8, $3, 0          // mtc0 t0, c0_entrylo1

Documentation of the MIPS architecture in various forms uses terms like page 
frame number (PFN) to refer to the bit range 31..6 in EntryLo0/1 which might 
be misinterpreted as some kind of multiplier of any configured page size. This 
is not the case.

Nor are the semantics of these registers consistent with various other 
registers (EntryHi, for instance) where one might interpret the available bits 
in their actual positions, which might mean that one merely sets the desired 
physical address combined with the control bits.

The JZ4780 manual, in its terseness, actually clarifies the matter concisely 
by indicating that the PFN corresponds to the bits from 12 upwards in the 
translated physical address, with a bit range of 25..6 actually being utilised 
by the hardware for this purpose and thus corresponding to bits 31..12 in the 
resulting physical address.

Therefore, the value used above, 0x0080001F, yields a PFN of (0x0080001F >> 6) 
or 0x20000, and thus the most significant bits of a physical address of 
(0x20000 << 12) or 0x20000000, or 512MB from the start of memory, which isn't 
what the code is meant to achieve. Thankfully, the author left a comment to 
state their intention instead of following the modern software industry 
practice of insisting that the code describes itself.

So, I changed the initial mapping to use the following with a 16MB page size:

li    $8, 0x0000001f     // even page @0MB, cached, dirty, valid, global
mtc0  $8, $2, 0          // mtc0 t0, c0_entrylo0
li    $8, 0x0004001f     // odd page @16MB, cached, dirty, valid, global
mtc0  $8, $3, 0          // mtc0 t0, c0_entrylo1

This made it possible to clear the ERL flag in the status register and copy 
modules around in memory using only KUSEG addresses, avoiding the odd mixing 
of KUSEG and KSEG0 addresses.

I also wanted to see if I could use the UART via its physical memory locations 
in the 0x10000000 region. I found that the following enabled this:

mtc0  $8, $5, 0          // mtc0 t0, c0_pagemask
li    $8, 0x00400017     // even page @256MB, uncached, dirty, valid, global
mtc0  $8, $2, 0          // mtc0 t0, c0_entrylo0
li    $8, 0x00440017     // odd page @256+16MB, uncached, dirty, valid, global
mtc0  $8, $3, 0          // mtc0 t0, c0_entrylo1

Changing the CI20's platform file configuration to not use KSEG1 to access the 
UART was successful, although this reliance on a global memory mapping is 
probably not desirable, and I imagine that the kernel unmaps these initial 
mappings, anyway. Consider this an experiment!

Reviewing my previous concern about caching issues and inconsistencies between 
memory regions, I think that the incorrect EntryLo1 value was causing 
confusion about where data was being copied. Indeed, having fixed this value, 
I can use KSEG0 addresses when initially moving modules and then KUSEG 
addresses when moving them into their final positions.

All of this gets the kernel started in various ways, as I previously achieved, 
but it still doesn't manage to complete its initialisation and still appears 
to hang in vprintf, so there is something else amiss.

Paul