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